1b4f9fe12SLen Brown /* 2b4f9fe12SLen Brown * toshiba_acpi.c - Toshiba Laptop ACPI Extras 3b4f9fe12SLen Brown * 4b4f9fe12SLen Brown * 5b4f9fe12SLen Brown * Copyright (C) 2002-2004 John Belmonte 6b4f9fe12SLen Brown * Copyright (C) 2008 Philip Langdale 76c3f6e6cSPierre Ducroquet * Copyright (C) 2010 Pierre Ducroquet 8548c4306SAzael Avalos * Copyright (C) 2014 Azael Avalos 9b4f9fe12SLen Brown * 10b4f9fe12SLen Brown * This program is free software; you can redistribute it and/or modify 11b4f9fe12SLen Brown * it under the terms of the GNU General Public License as published by 12b4f9fe12SLen Brown * the Free Software Foundation; either version 2 of the License, or 13b4f9fe12SLen Brown * (at your option) any later version. 14b4f9fe12SLen Brown * 15b4f9fe12SLen Brown * This program is distributed in the hope that it will be useful, 16b4f9fe12SLen Brown * but WITHOUT ANY WARRANTY; without even the implied warranty of 17b4f9fe12SLen Brown * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18b4f9fe12SLen Brown * GNU General Public License for more details. 19b4f9fe12SLen Brown * 20b4f9fe12SLen Brown * You should have received a copy of the GNU General Public License 21b4f9fe12SLen Brown * along with this program; if not, write to the Free Software 22b4f9fe12SLen Brown * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23b4f9fe12SLen Brown * 24b4f9fe12SLen Brown * 25b4f9fe12SLen Brown * The devolpment page for this driver is located at 26b4f9fe12SLen Brown * http://memebeam.org/toys/ToshibaAcpiDriver. 27b4f9fe12SLen Brown * 28b4f9fe12SLen Brown * Credits: 29b4f9fe12SLen Brown * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse 30b4f9fe12SLen Brown * engineering the Windows drivers 31b4f9fe12SLen Brown * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 32b4f9fe12SLen Brown * Rob Miller - TV out and hotkeys help 33b4f9fe12SLen Brown * 34b4f9fe12SLen Brown * 35b4f9fe12SLen Brown * TODO 36b4f9fe12SLen Brown * 37b4f9fe12SLen Brown */ 38b4f9fe12SLen Brown 397e33460dSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 407e33460dSJoe Perches 41548c4306SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.20" 42b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION 1 43b4f9fe12SLen Brown 44b4f9fe12SLen Brown #include <linux/kernel.h> 45b4f9fe12SLen Brown #include <linux/module.h> 46b4f9fe12SLen Brown #include <linux/init.h> 47b4f9fe12SLen Brown #include <linux/types.h> 48b4f9fe12SLen Brown #include <linux/proc_fs.h> 49936c8bcdSAlexey Dobriyan #include <linux/seq_file.h> 50b4f9fe12SLen Brown #include <linux/backlight.h> 51b4f9fe12SLen Brown #include <linux/rfkill.h> 526335e4d5SMatthew Garrett #include <linux/input.h> 53384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h> 546c3f6e6cSPierre Ducroquet #include <linux/leds.h> 555a0e3ad6STejun Heo #include <linux/slab.h> 5629cd293fSSeth Forshee #include <linux/workqueue.h> 5729cd293fSSeth Forshee #include <linux/i8042.h> 588b48463fSLv Zheng #include <linux/acpi.h> 59fe808bfbSTakashi Iwai #include <linux/dmi.h> 60b4f9fe12SLen Brown #include <asm/uaccess.h> 61b4f9fe12SLen Brown 62b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 63b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 64b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 65b4f9fe12SLen Brown 66f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 67f11f999eSSeth Forshee 6829cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */ 6929cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e 7029cd293fSSeth Forshee 71b4f9fe12SLen Brown /* Toshiba ACPI method paths */ 72b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 73b4f9fe12SLen Brown 74258c5903SAzael Avalos /* The Toshiba configuration interface is composed of the HCI and the SCI, 75258c5903SAzael Avalos * which are defined as follows: 76b4f9fe12SLen Brown * 77b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to 78b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call 79b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface. 80b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for 81b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value), 82b4f9fe12SLen Brown * so this is still useful. 8384a6273fSAzael Avalos * 8484a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to 8584a6273fSAzael Avalos * conceal differences in hardware between different models. 86b4f9fe12SLen Brown */ 87b4f9fe12SLen Brown 88258c5903SAzael Avalos #define TCI_WORDS 6 89b4f9fe12SLen Brown 90b4f9fe12SLen Brown /* operations */ 91b4f9fe12SLen Brown #define HCI_SET 0xff00 92b4f9fe12SLen Brown #define HCI_GET 0xfe00 9384a6273fSAzael Avalos #define SCI_OPEN 0xf100 9484a6273fSAzael Avalos #define SCI_CLOSE 0xf200 9584a6273fSAzael Avalos #define SCI_GET 0xf300 9684a6273fSAzael Avalos #define SCI_SET 0xf400 97b4f9fe12SLen Brown 98b4f9fe12SLen Brown /* return codes */ 991864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 1001864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 1011864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 1021864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 1031864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 1041864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 1051864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 1061864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 1071864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 1081864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 1091864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1101864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 111*98fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 112b4f9fe12SLen Brown 113b4f9fe12SLen Brown /* registers */ 114b4f9fe12SLen Brown #define HCI_FAN 0x0004 115121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 116b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 117b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 118b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 119b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 120b4f9fe12SLen Brown #define HCI_WIRELESS 0x0056 1215a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 122360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 123def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1245a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 125fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 126e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 127360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 128172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 1299d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 130b4f9fe12SLen Brown 131b4f9fe12SLen Brown /* field definitions */ 1325a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13329cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 13429cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE 0x09 135b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 136b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 137b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 138360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 139b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 140b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 141b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 142b4f9fe12SLen Brown #define HCI_WIRELESS_KILL_SWITCH 0x01 143b4f9fe12SLen Brown #define HCI_WIRELESS_BT_PRESENT 0x0f 144b4f9fe12SLen Brown #define HCI_WIRELESS_BT_ATTACH 0x40 145b4f9fe12SLen Brown #define HCI_WIRELESS_BT_POWER 0x80 14693f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 147360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 148360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 14993f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 15093f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 15193f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 152e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 153e26ffe51SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x30000 154e26ffe51SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x30009 155e26ffe51SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x30021 156182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 157182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 158182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 159182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 160bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 161b4f9fe12SLen Brown 162135740deSSeth Forshee struct toshiba_acpi_dev { 163135740deSSeth Forshee struct acpi_device *acpi_dev; 164135740deSSeth Forshee const char *method_hci; 165135740deSSeth Forshee struct rfkill *bt_rfk; 166135740deSSeth Forshee struct input_dev *hotkey_dev; 16729cd293fSSeth Forshee struct work_struct hotkey_work; 168135740deSSeth Forshee struct backlight_device *backlight_dev; 169135740deSSeth Forshee struct led_classdev led_dev; 170360f0f39SAzael Avalos struct led_classdev kbd_led; 171def6c4e2SAzael Avalos struct led_classdev eco_led; 17236d03f93SSeth Forshee 173135740deSSeth Forshee int force_fan; 174135740deSSeth Forshee int last_key_event; 175135740deSSeth Forshee int key_event_valid; 17693f8c16dSAzael Avalos int kbd_type; 177360f0f39SAzael Avalos int kbd_mode; 178360f0f39SAzael Avalos int kbd_time; 179182bcaa5SAzael Avalos int usbsc_bat_level; 180135740deSSeth Forshee 181592b746cSDan Carpenter unsigned int illumination_supported:1; 182592b746cSDan Carpenter unsigned int video_supported:1; 183592b746cSDan Carpenter unsigned int fan_supported:1; 184592b746cSDan Carpenter unsigned int system_event_supported:1; 18529cd293fSSeth Forshee unsigned int ntfy_supported:1; 18629cd293fSSeth Forshee unsigned int info_supported:1; 187121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 188360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 189360f0f39SAzael Avalos unsigned int kbd_led_registered:1; 1909d8658acSAzael Avalos unsigned int touchpad_supported:1; 191def6c4e2SAzael Avalos unsigned int eco_supported:1; 1925a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 193e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 194bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 195172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 196360f0f39SAzael Avalos unsigned int sysfs_created:1; 19736d03f93SSeth Forshee 198135740deSSeth Forshee struct mutex mutex; 199135740deSSeth Forshee }; 200135740deSSeth Forshee 20129cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 20229cd293fSSeth Forshee 203b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 204b4f9fe12SLen Brown {"TOS6200", 0}, 20563a9e016SOndrej Zary {"TOS6207", 0}, 206b4f9fe12SLen Brown {"TOS6208", 0}, 207b4f9fe12SLen Brown {"TOS1900", 0}, 208b4f9fe12SLen Brown {"", 0}, 209b4f9fe12SLen Brown }; 210b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 211b4f9fe12SLen Brown 212b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 213fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 214384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 215384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 216384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 217408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 218af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 219af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 220384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 221384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 222384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 223384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 224384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 225384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 226384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 227384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 228af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 229a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 230384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 231384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 232384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 233384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 235384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 236384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 237384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 238408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 239408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 240408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 241408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 242408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 243384a7cd9SDmitry Torokhov { KE_END, 0 }, 2446335e4d5SMatthew Garrett }; 2456335e4d5SMatthew Garrett 246fe808bfbSTakashi Iwai /* alternative keymap */ 247fe808bfbSTakashi Iwai static const struct dmi_system_id toshiba_alt_keymap_dmi[] = { 248fe808bfbSTakashi Iwai { 249fe808bfbSTakashi Iwai .matches = { 250fe808bfbSTakashi Iwai DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 251fe808bfbSTakashi Iwai DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"), 252fe808bfbSTakashi Iwai }, 253fe808bfbSTakashi Iwai }, 254e6efad7fSAzael Avalos { 255e6efad7fSAzael Avalos .matches = { 256e6efad7fSAzael Avalos DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 257e6efad7fSAzael Avalos DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"), 258e6efad7fSAzael Avalos }, 259e6efad7fSAzael Avalos }, 260b1bde689SAaron Lu { 261b1bde689SAaron Lu .matches = { 262b1bde689SAaron Lu DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 263b1bde689SAaron Lu DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A50-A"), 264b1bde689SAaron Lu }, 265b1bde689SAaron Lu }, 266fe808bfbSTakashi Iwai {} 267fe808bfbSTakashi Iwai }; 268fe808bfbSTakashi Iwai 269fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 270fe808bfbSTakashi Iwai { KE_KEY, 0x157, { KEY_MUTE } }, 271fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 272fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 273e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 274fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 275fe808bfbSTakashi Iwai { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 276fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 277fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 278fe808bfbSTakashi Iwai { KE_KEY, 0x158, { KEY_WLAN } }, 279fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 280fe808bfbSTakashi Iwai { KE_END, 0 }, 281fe808bfbSTakashi Iwai }; 282fe808bfbSTakashi Iwai 283b4f9fe12SLen Brown /* utility 284b4f9fe12SLen Brown */ 285b4f9fe12SLen Brown 286b4f9fe12SLen Brown static __inline__ void _set_bit(u32 * word, u32 mask, int value) 287b4f9fe12SLen Brown { 288b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 289b4f9fe12SLen Brown } 290b4f9fe12SLen Brown 291b4f9fe12SLen Brown /* acpi interface wrappers 292b4f9fe12SLen Brown */ 293b4f9fe12SLen Brown 294b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 295b4f9fe12SLen Brown { 296b4f9fe12SLen Brown acpi_status status; 297b4f9fe12SLen Brown 298619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 29932bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 300b4f9fe12SLen Brown } 301b4f9fe12SLen Brown 302258c5903SAzael Avalos /* Perform a raw configuration call. Here we don't care about input or output 303258c5903SAzael Avalos * buffer format. 304b4f9fe12SLen Brown */ 305258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 306258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 307b4f9fe12SLen Brown { 308b4f9fe12SLen Brown struct acpi_object_list params; 309258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 310b4f9fe12SLen Brown struct acpi_buffer results; 311258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 312b4f9fe12SLen Brown acpi_status status; 313b4f9fe12SLen Brown int i; 314b4f9fe12SLen Brown 315258c5903SAzael Avalos params.count = TCI_WORDS; 316b4f9fe12SLen Brown params.pointer = in_objs; 317258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 318b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 319b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 320b4f9fe12SLen Brown } 321b4f9fe12SLen Brown 322b4f9fe12SLen Brown results.length = sizeof(out_objs); 323b4f9fe12SLen Brown results.pointer = out_objs; 324b4f9fe12SLen Brown 3256e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3266e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 327b4f9fe12SLen Brown &results); 328258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 329b4f9fe12SLen Brown for (i = 0; i < out_objs->package.count; ++i) { 330b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 331b4f9fe12SLen Brown } 332b4f9fe12SLen Brown } 333b4f9fe12SLen Brown 334b4f9fe12SLen Brown return status; 335b4f9fe12SLen Brown } 336b4f9fe12SLen Brown 337b4f9fe12SLen Brown /* common hci tasks (get or set one or two value) 338b4f9fe12SLen Brown * 339b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 340b4f9fe12SLen Brown * may be useful (such as "not supported"). 341b4f9fe12SLen Brown */ 342b4f9fe12SLen Brown 343893f3f62SAzael Avalos static u32 hci_write1(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 344b4f9fe12SLen Brown { 345258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 346258c5903SAzael Avalos u32 out[TCI_WORDS]; 347258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 348893f3f62SAzael Avalos 349893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 350b4f9fe12SLen Brown } 351b4f9fe12SLen Brown 352893f3f62SAzael Avalos static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 353b4f9fe12SLen Brown { 354258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 355258c5903SAzael Avalos u32 out[TCI_WORDS]; 356258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 357893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 358893f3f62SAzael Avalos return TOS_FAILURE; 359893f3f62SAzael Avalos 360b4f9fe12SLen Brown *out1 = out[2]; 361893f3f62SAzael Avalos 362893f3f62SAzael Avalos return out[0]; 363b4f9fe12SLen Brown } 364b4f9fe12SLen Brown 365893f3f62SAzael Avalos static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2) 366b4f9fe12SLen Brown { 367258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 }; 368258c5903SAzael Avalos u32 out[TCI_WORDS]; 369258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 370893f3f62SAzael Avalos 371893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 372b4f9fe12SLen Brown } 373b4f9fe12SLen Brown 374893f3f62SAzael Avalos static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2) 375b4f9fe12SLen Brown { 376258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 }; 377258c5903SAzael Avalos u32 out[TCI_WORDS]; 378258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 379893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 380893f3f62SAzael Avalos return TOS_FAILURE; 381893f3f62SAzael Avalos 382b4f9fe12SLen Brown *out1 = out[2]; 383b4f9fe12SLen Brown *out2 = out[3]; 384893f3f62SAzael Avalos 385893f3f62SAzael Avalos return out[0]; 386b4f9fe12SLen Brown } 387b4f9fe12SLen Brown 38884a6273fSAzael Avalos /* common sci tasks 38984a6273fSAzael Avalos */ 39084a6273fSAzael Avalos 39184a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 39284a6273fSAzael Avalos { 393258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 394258c5903SAzael Avalos u32 out[TCI_WORDS]; 39584a6273fSAzael Avalos acpi_status status; 39684a6273fSAzael Avalos 397258c5903SAzael Avalos status = tci_raw(dev, in, out); 3981864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 39984a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 40084a6273fSAzael Avalos return 0; 40184a6273fSAzael Avalos } 40284a6273fSAzael Avalos 4031864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 40484a6273fSAzael Avalos return 1; 4051864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 40684a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 40784a6273fSAzael Avalos return 1; 408fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 409fa465739SAzael Avalos /* Some BIOSes do not have the SCI open/close functions 410fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 411fa465739SAzael Avalos * register some supported features. 412fa465739SAzael Avalos * 413fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 414fa465739SAzael Avalos * supported features work. 415fa465739SAzael Avalos * 416fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 417fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 418fa465739SAzael Avalos * and thus, not registering support for the queried feature. 419fa465739SAzael Avalos */ 420fa465739SAzael Avalos return 1; 4211864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 42284a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 42384a6273fSAzael Avalos } 42484a6273fSAzael Avalos 42584a6273fSAzael Avalos return 0; 42684a6273fSAzael Avalos } 42784a6273fSAzael Avalos 42884a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 42984a6273fSAzael Avalos { 430258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 431258c5903SAzael Avalos u32 out[TCI_WORDS]; 43284a6273fSAzael Avalos acpi_status status; 43384a6273fSAzael Avalos 434258c5903SAzael Avalos status = tci_raw(dev, in, out); 4351864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 43684a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 43784a6273fSAzael Avalos return; 43884a6273fSAzael Avalos } 43984a6273fSAzael Avalos 4401864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 44184a6273fSAzael Avalos return; 4421864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 44384a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4441864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 44584a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 44684a6273fSAzael Avalos } 44784a6273fSAzael Avalos 448893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 44984a6273fSAzael Avalos { 450258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 451258c5903SAzael Avalos u32 out[TCI_WORDS]; 452258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 453893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 454893f3f62SAzael Avalos return TOS_FAILURE; 455893f3f62SAzael Avalos 45684a6273fSAzael Avalos *out1 = out[2]; 457893f3f62SAzael Avalos 458893f3f62SAzael Avalos return out[0]; 45984a6273fSAzael Avalos } 46084a6273fSAzael Avalos 461893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 46284a6273fSAzael Avalos { 463258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 464258c5903SAzael Avalos u32 out[TCI_WORDS]; 465258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 466893f3f62SAzael Avalos 467893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 46884a6273fSAzael Avalos } 46984a6273fSAzael Avalos 4706c3f6e6cSPierre Ducroquet /* Illumination support */ 471135740deSSeth Forshee static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4726c3f6e6cSPierre Ducroquet { 473258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 474258c5903SAzael Avalos u32 out[TCI_WORDS]; 4756c3f6e6cSPierre Ducroquet acpi_status status; 4766c3f6e6cSPierre Ducroquet 477fdb79081SAzael Avalos if (!sci_open(dev)) 478fdb79081SAzael Avalos return 0; 479fdb79081SAzael Avalos 480258c5903SAzael Avalos status = tci_raw(dev, in, out); 481fdb79081SAzael Avalos sci_close(dev); 4821864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 483fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 484fdb79081SAzael Avalos return 0; 4851864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 4867e33460dSJoe Perches pr_info("Illumination device not available\n"); 4876c3f6e6cSPierre Ducroquet return 0; 4886c3f6e6cSPierre Ducroquet } 489fdb79081SAzael Avalos 4906c3f6e6cSPierre Ducroquet return 1; 4916c3f6e6cSPierre Ducroquet } 4926c3f6e6cSPierre Ducroquet 4936c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4946c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4956c3f6e6cSPierre Ducroquet { 496135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 497135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 498fdb79081SAzael Avalos u32 state, result; 4996c3f6e6cSPierre Ducroquet 5006c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 501fdb79081SAzael Avalos if (!sci_open(dev)) 5026c3f6e6cSPierre Ducroquet return; 5036c3f6e6cSPierre Ducroquet 504fdb79081SAzael Avalos /* Switch the illumination on/off */ 505fdb79081SAzael Avalos state = brightness ? 1 : 0; 506893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 507fdb79081SAzael Avalos sci_close(dev); 508893f3f62SAzael Avalos if (result == TOS_FAILURE) { 509fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 510fdb79081SAzael Avalos return; 5111864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 512fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 5136c3f6e6cSPierre Ducroquet return; 5146c3f6e6cSPierre Ducroquet } 5156c3f6e6cSPierre Ducroquet } 5166c3f6e6cSPierre Ducroquet 5176c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 5186c3f6e6cSPierre Ducroquet { 519135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 520135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 521fdb79081SAzael Avalos u32 state, result; 5226c3f6e6cSPierre Ducroquet 5236c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 524fdb79081SAzael Avalos if (!sci_open(dev)) 5256c3f6e6cSPierre Ducroquet return LED_OFF; 5266c3f6e6cSPierre Ducroquet 5276c3f6e6cSPierre Ducroquet /* Check the illumination */ 528893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 529fdb79081SAzael Avalos sci_close(dev); 530893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 531fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 532fdb79081SAzael Avalos return LED_OFF; 5331864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 534fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 5356c3f6e6cSPierre Ducroquet return LED_OFF; 5366c3f6e6cSPierre Ducroquet } 5376c3f6e6cSPierre Ducroquet 538fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5396c3f6e6cSPierre Ducroquet } 5406c3f6e6cSPierre Ducroquet 541360f0f39SAzael Avalos /* KBD Illumination */ 54293f8c16dSAzael Avalos static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 54393f8c16dSAzael Avalos { 544258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 545258c5903SAzael Avalos u32 out[TCI_WORDS]; 54693f8c16dSAzael Avalos acpi_status status; 54793f8c16dSAzael Avalos 54893f8c16dSAzael Avalos if (!sci_open(dev)) 54993f8c16dSAzael Avalos return 0; 55093f8c16dSAzael Avalos 551258c5903SAzael Avalos status = tci_raw(dev, in, out); 55293f8c16dSAzael Avalos sci_close(dev); 5531864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 55493f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 55593f8c16dSAzael Avalos return 0; 5561864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 55793f8c16dSAzael Avalos pr_info("Keyboard illumination not available\n"); 55893f8c16dSAzael Avalos return 0; 55993f8c16dSAzael Avalos } 56093f8c16dSAzael Avalos 56193f8c16dSAzael Avalos /* Check for keyboard backlight timeout max value, 56293f8c16dSAzael Avalos * previous kbd backlight implementation set this to 56393f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 56493f8c16dSAzael Avalos * to 0x3c001a, use this to distinguish between them 56593f8c16dSAzael Avalos */ 56693f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 56793f8c16dSAzael Avalos dev->kbd_type = 2; 56893f8c16dSAzael Avalos else 56993f8c16dSAzael Avalos dev->kbd_type = 1; 57093f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 57193f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 57293f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 57393f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 57493f8c16dSAzael Avalos 57593f8c16dSAzael Avalos return 1; 57693f8c16dSAzael Avalos } 57793f8c16dSAzael Avalos 578360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 579360f0f39SAzael Avalos { 580360f0f39SAzael Avalos u32 result; 581360f0f39SAzael Avalos 582360f0f39SAzael Avalos if (!sci_open(dev)) 583360f0f39SAzael Avalos return -EIO; 584360f0f39SAzael Avalos 585893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 586360f0f39SAzael Avalos sci_close(dev); 587893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 588360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 589360f0f39SAzael Avalos return -EIO; 5901864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 591360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 592360f0f39SAzael Avalos return -ENODEV; 593360f0f39SAzael Avalos } 594360f0f39SAzael Avalos 595360f0f39SAzael Avalos return 0; 596360f0f39SAzael Avalos } 597360f0f39SAzael Avalos 598360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 599360f0f39SAzael Avalos { 600360f0f39SAzael Avalos u32 result; 601360f0f39SAzael Avalos 602360f0f39SAzael Avalos if (!sci_open(dev)) 603360f0f39SAzael Avalos return -EIO; 604360f0f39SAzael Avalos 605893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 606360f0f39SAzael Avalos sci_close(dev); 607893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 608360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 609360f0f39SAzael Avalos return -EIO; 6101864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 611360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 612360f0f39SAzael Avalos return -ENODEV; 613360f0f39SAzael Avalos } 614360f0f39SAzael Avalos 615360f0f39SAzael Avalos return 0; 616360f0f39SAzael Avalos } 617360f0f39SAzael Avalos 618360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 619360f0f39SAzael Avalos { 620360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 621360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 622360f0f39SAzael Avalos u32 state, result; 623360f0f39SAzael Avalos 624360f0f39SAzael Avalos /* Check the keyboard backlight state */ 625893f3f62SAzael Avalos result = hci_read1(dev, HCI_KBD_ILLUMINATION, &state); 626893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 627360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 628360f0f39SAzael Avalos return LED_OFF; 6291864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 630360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 631360f0f39SAzael Avalos return LED_OFF; 632360f0f39SAzael Avalos } 633360f0f39SAzael Avalos 634360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 635360f0f39SAzael Avalos } 636360f0f39SAzael Avalos 637360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 638360f0f39SAzael Avalos enum led_brightness brightness) 639360f0f39SAzael Avalos { 640360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 641360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 642360f0f39SAzael Avalos u32 state, result; 643360f0f39SAzael Avalos 644360f0f39SAzael Avalos /* Set the keyboard backlight state */ 645360f0f39SAzael Avalos state = brightness ? 1 : 0; 646893f3f62SAzael Avalos result = hci_write1(dev, HCI_KBD_ILLUMINATION, state); 647893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 648360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 649360f0f39SAzael Avalos return; 6501864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 651360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 652360f0f39SAzael Avalos return; 653360f0f39SAzael Avalos } 654360f0f39SAzael Avalos } 655360f0f39SAzael Avalos 6569d8658acSAzael Avalos /* TouchPad support */ 6579d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6589d8658acSAzael Avalos { 6599d8658acSAzael Avalos u32 result; 6609d8658acSAzael Avalos 6619d8658acSAzael Avalos if (!sci_open(dev)) 6629d8658acSAzael Avalos return -EIO; 6639d8658acSAzael Avalos 664893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6659d8658acSAzael Avalos sci_close(dev); 666893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6679d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 6689d8658acSAzael Avalos return -EIO; 6691864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6709d8658acSAzael Avalos return -ENODEV; 6719d8658acSAzael Avalos } 6729d8658acSAzael Avalos 6739d8658acSAzael Avalos return 0; 6749d8658acSAzael Avalos } 6759d8658acSAzael Avalos 6769d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6779d8658acSAzael Avalos { 6789d8658acSAzael Avalos u32 result; 6799d8658acSAzael Avalos 6809d8658acSAzael Avalos if (!sci_open(dev)) 6819d8658acSAzael Avalos return -EIO; 6829d8658acSAzael Avalos 683893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6849d8658acSAzael Avalos sci_close(dev); 685893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6869d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 6879d8658acSAzael Avalos return -EIO; 6881864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6899d8658acSAzael Avalos return -ENODEV; 6909d8658acSAzael Avalos } 6919d8658acSAzael Avalos 6929d8658acSAzael Avalos return 0; 6939d8658acSAzael Avalos } 6949d8658acSAzael Avalos 695def6c4e2SAzael Avalos /* Eco Mode support */ 696def6c4e2SAzael Avalos static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 697def6c4e2SAzael Avalos { 698def6c4e2SAzael Avalos acpi_status status; 699*98fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 700258c5903SAzael Avalos u32 out[TCI_WORDS]; 701def6c4e2SAzael Avalos 702258c5903SAzael Avalos status = tci_raw(dev, in, out); 703*98fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 704*98fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 705*98fc4ec6SAzael Avalos } else if (out[0] == TOS_NOT_INSTALLED) { 706*98fc4ec6SAzael Avalos pr_info("ECO led not installed"); 707*98fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 708*98fc4ec6SAzael Avalos /* If we receive 0x8300 (Input Data Error), it means that the 709*98fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 710*98fc4ec6SAzael Avalos * parameters. 711*98fc4ec6SAzael Avalos * 712*98fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 713*98fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 714*98fc4ec6SAzael Avalos * bail out otherwise. 715*98fc4ec6SAzael Avalos */ 716*98fc4ec6SAzael Avalos in[3] = 1; 717*98fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 718*98fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) 719*98fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 720*98fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 721*98fc4ec6SAzael Avalos return 1; 722def6c4e2SAzael Avalos } 723def6c4e2SAzael Avalos 724*98fc4ec6SAzael Avalos return 0; 725def6c4e2SAzael Avalos } 726def6c4e2SAzael Avalos 727def6c4e2SAzael Avalos static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev) 728def6c4e2SAzael Avalos { 729def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 730def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 731258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 732258c5903SAzael Avalos u32 out[TCI_WORDS]; 733def6c4e2SAzael Avalos acpi_status status; 734def6c4e2SAzael Avalos 735258c5903SAzael Avalos status = tci_raw(dev, in, out); 7361864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 737def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 738def6c4e2SAzael Avalos return LED_OFF; 739def6c4e2SAzael Avalos } 740def6c4e2SAzael Avalos 741def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 742def6c4e2SAzael Avalos } 743def6c4e2SAzael Avalos 744def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 745def6c4e2SAzael Avalos enum led_brightness brightness) 746def6c4e2SAzael Avalos { 747def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 748def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 749258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 750258c5903SAzael Avalos u32 out[TCI_WORDS]; 751def6c4e2SAzael Avalos acpi_status status; 752def6c4e2SAzael Avalos 753def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 754def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 755258c5903SAzael Avalos status = tci_raw(dev, in, out); 7561864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 757def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 758def6c4e2SAzael Avalos return; 759def6c4e2SAzael Avalos } 760def6c4e2SAzael Avalos } 761def6c4e2SAzael Avalos 7625a2813e9SAzael Avalos /* Accelerometer support */ 7635a2813e9SAzael Avalos static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) 7645a2813e9SAzael Avalos { 765258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 766258c5903SAzael Avalos u32 out[TCI_WORDS]; 7675a2813e9SAzael Avalos acpi_status status; 7685a2813e9SAzael Avalos 7695a2813e9SAzael Avalos /* Check if the accelerometer call exists, 7705a2813e9SAzael Avalos * this call also serves as initialization 7715a2813e9SAzael Avalos */ 772258c5903SAzael Avalos status = tci_raw(dev, in, out); 7731864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7745a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7755a2813e9SAzael Avalos return -EIO; 7761864bbc2SAzael Avalos } else if (out[0] == TOS_DATA_NOT_AVAILABLE || 7771864bbc2SAzael Avalos out[0] == TOS_NOT_INITIALIZED) { 7785a2813e9SAzael Avalos pr_err("Accelerometer not initialized\n"); 7795a2813e9SAzael Avalos return -EIO; 7801864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 7815a2813e9SAzael Avalos pr_info("Accelerometer not supported\n"); 7825a2813e9SAzael Avalos return -ENODEV; 7835a2813e9SAzael Avalos } 7845a2813e9SAzael Avalos 7855a2813e9SAzael Avalos return 0; 7865a2813e9SAzael Avalos } 7875a2813e9SAzael Avalos 7885a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7895a2813e9SAzael Avalos u32 *xy, u32 *z) 7905a2813e9SAzael Avalos { 791258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 792258c5903SAzael Avalos u32 out[TCI_WORDS]; 7935a2813e9SAzael Avalos acpi_status status; 7945a2813e9SAzael Avalos 7955a2813e9SAzael Avalos /* Check the Accelerometer status */ 796258c5903SAzael Avalos status = tci_raw(dev, in, out); 7971864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7985a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7995a2813e9SAzael Avalos return -EIO; 8005a2813e9SAzael Avalos } 8015a2813e9SAzael Avalos 8025a2813e9SAzael Avalos *xy = out[2]; 8035a2813e9SAzael Avalos *z = out[4]; 8045a2813e9SAzael Avalos 8055a2813e9SAzael Avalos return 0; 8065a2813e9SAzael Avalos } 8075a2813e9SAzael Avalos 808e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 809e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 810e26ffe51SAzael Avalos u32 *mode) 811e26ffe51SAzael Avalos { 812e26ffe51SAzael Avalos u32 result; 813e26ffe51SAzael Avalos 814e26ffe51SAzael Avalos if (!sci_open(dev)) 815e26ffe51SAzael Avalos return -EIO; 816e26ffe51SAzael Avalos 817e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 818e26ffe51SAzael Avalos sci_close(dev); 819e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 820e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 821e26ffe51SAzael Avalos return -EIO; 822e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 823e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 824e26ffe51SAzael Avalos return -ENODEV; 825e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 826e26ffe51SAzael Avalos return -EIO; 827e26ffe51SAzael Avalos } 828e26ffe51SAzael Avalos 829e26ffe51SAzael Avalos return 0; 830e26ffe51SAzael Avalos } 831e26ffe51SAzael Avalos 832e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 833e26ffe51SAzael Avalos u32 mode) 834e26ffe51SAzael Avalos { 835e26ffe51SAzael Avalos u32 result; 836e26ffe51SAzael Avalos 837e26ffe51SAzael Avalos if (!sci_open(dev)) 838e26ffe51SAzael Avalos return -EIO; 839e26ffe51SAzael Avalos 840e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 841e26ffe51SAzael Avalos sci_close(dev); 842e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 843e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 844e26ffe51SAzael Avalos return -EIO; 845e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 846e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 847e26ffe51SAzael Avalos return -ENODEV; 848e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 849e26ffe51SAzael Avalos return -EIO; 850e26ffe51SAzael Avalos } 851e26ffe51SAzael Avalos 852e26ffe51SAzael Avalos return 0; 853e26ffe51SAzael Avalos } 854e26ffe51SAzael Avalos 855182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 856182bcaa5SAzael Avalos u32 *mode) 857182bcaa5SAzael Avalos { 858182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 859182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 860182bcaa5SAzael Avalos acpi_status status; 861182bcaa5SAzael Avalos 862182bcaa5SAzael Avalos if (!sci_open(dev)) 863182bcaa5SAzael Avalos return -EIO; 864182bcaa5SAzael Avalos 865182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 866182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 867182bcaa5SAzael Avalos sci_close(dev); 868182bcaa5SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 869182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 870182bcaa5SAzael Avalos return -EIO; 871182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 872182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 873182bcaa5SAzael Avalos return -ENODEV; 874182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 875182bcaa5SAzael Avalos return -EIO; 876182bcaa5SAzael Avalos } 877182bcaa5SAzael Avalos 878182bcaa5SAzael Avalos *mode = out[2]; 879182bcaa5SAzael Avalos 880182bcaa5SAzael Avalos return 0; 881182bcaa5SAzael Avalos } 882182bcaa5SAzael Avalos 883182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 884182bcaa5SAzael Avalos u32 mode) 885182bcaa5SAzael Avalos { 886182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 887182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 888182bcaa5SAzael Avalos acpi_status status; 889182bcaa5SAzael Avalos 890182bcaa5SAzael Avalos if (!sci_open(dev)) 891182bcaa5SAzael Avalos return -EIO; 892182bcaa5SAzael Avalos 893182bcaa5SAzael Avalos in[2] = mode; 894182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 895182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 896182bcaa5SAzael Avalos sci_close(dev); 897182bcaa5SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 898182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 899182bcaa5SAzael Avalos return -EIO; 900182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 901182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 902182bcaa5SAzael Avalos return -ENODEV; 903182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 904182bcaa5SAzael Avalos return -EIO; 905182bcaa5SAzael Avalos } 906182bcaa5SAzael Avalos 907182bcaa5SAzael Avalos return 0; 908182bcaa5SAzael Avalos } 909182bcaa5SAzael Avalos 910bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 911bb3fe01fSAzael Avalos u32 *state) 912bb3fe01fSAzael Avalos { 913bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 914bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 915bb3fe01fSAzael Avalos acpi_status status; 916bb3fe01fSAzael Avalos 917bb3fe01fSAzael Avalos if (!sci_open(dev)) 918bb3fe01fSAzael Avalos return -EIO; 919bb3fe01fSAzael Avalos 920bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 921bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 922bb3fe01fSAzael Avalos sci_close(dev); 923bb3fe01fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 924bb3fe01fSAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 925bb3fe01fSAzael Avalos return -EIO; 926bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED || 927bb3fe01fSAzael Avalos out[0] == TOS_INPUT_DATA_ERROR) { 928bb3fe01fSAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 929bb3fe01fSAzael Avalos return -ENODEV; 930bb3fe01fSAzael Avalos } 931bb3fe01fSAzael Avalos 932bb3fe01fSAzael Avalos *state = out[2]; 933bb3fe01fSAzael Avalos 934bb3fe01fSAzael Avalos return 0; 935bb3fe01fSAzael Avalos } 936bb3fe01fSAzael Avalos 937bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 938bb3fe01fSAzael Avalos u32 state) 939bb3fe01fSAzael Avalos { 940bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 941bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 942bb3fe01fSAzael Avalos acpi_status status; 943bb3fe01fSAzael Avalos 944bb3fe01fSAzael Avalos if (!sci_open(dev)) 945bb3fe01fSAzael Avalos return -EIO; 946bb3fe01fSAzael Avalos 947bb3fe01fSAzael Avalos in[2] = state; 948bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 949bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 950bb3fe01fSAzael Avalos sci_close(dev); 951bb3fe01fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 952bb3fe01fSAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 953bb3fe01fSAzael Avalos return -EIO; 954bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 955bb3fe01fSAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 956bb3fe01fSAzael Avalos return -ENODEV; 957bb3fe01fSAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 958bb3fe01fSAzael Avalos return -EIO; 959bb3fe01fSAzael Avalos } 960bb3fe01fSAzael Avalos 961bb3fe01fSAzael Avalos return 0; 962bb3fe01fSAzael Avalos } 963bb3fe01fSAzael Avalos 964172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 965172ce0a9SAzael Avalos { 966172ce0a9SAzael Avalos u32 result; 967172ce0a9SAzael Avalos 968172ce0a9SAzael Avalos if (!sci_open(dev)) 969172ce0a9SAzael Avalos return -EIO; 970172ce0a9SAzael Avalos 971172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 972172ce0a9SAzael Avalos sci_close(dev); 973172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 974172ce0a9SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 975172ce0a9SAzael Avalos return -EIO; 976172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 977172ce0a9SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 978172ce0a9SAzael Avalos return -ENODEV; 979172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 980172ce0a9SAzael Avalos return -EIO; 981172ce0a9SAzael Avalos } 982172ce0a9SAzael Avalos 983172ce0a9SAzael Avalos return 0; 984172ce0a9SAzael Avalos } 985172ce0a9SAzael Avalos 986172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 987172ce0a9SAzael Avalos { 988172ce0a9SAzael Avalos u32 result; 989172ce0a9SAzael Avalos 990172ce0a9SAzael Avalos if (!sci_open(dev)) 991172ce0a9SAzael Avalos return -EIO; 992172ce0a9SAzael Avalos 993172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 994172ce0a9SAzael Avalos sci_close(dev); 995172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 996172ce0a9SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 997172ce0a9SAzael Avalos return -EIO; 998172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 999172ce0a9SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 1000172ce0a9SAzael Avalos return -ENODEV; 1001172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1002172ce0a9SAzael Avalos return -EIO; 1003172ce0a9SAzael Avalos } 1004172ce0a9SAzael Avalos 1005172ce0a9SAzael Avalos return 0; 1006172ce0a9SAzael Avalos } 1007172ce0a9SAzael Avalos 1008b4f9fe12SLen Brown /* Bluetooth rfkill handlers */ 1009b4f9fe12SLen Brown 1010135740deSSeth Forshee static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present) 1011b4f9fe12SLen Brown { 1012b4f9fe12SLen Brown u32 hci_result; 1013b4f9fe12SLen Brown u32 value, value2; 1014b4f9fe12SLen Brown 1015b4f9fe12SLen Brown value = 0; 1016b4f9fe12SLen Brown value2 = 0; 1017893f3f62SAzael Avalos hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); 10181864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1019b4f9fe12SLen Brown *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false; 1020b4f9fe12SLen Brown 1021b4f9fe12SLen Brown return hci_result; 1022b4f9fe12SLen Brown } 1023b4f9fe12SLen Brown 1024135740deSSeth Forshee static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state) 1025b4f9fe12SLen Brown { 1026b4f9fe12SLen Brown u32 hci_result; 1027b4f9fe12SLen Brown u32 value, value2; 1028b4f9fe12SLen Brown 1029b4f9fe12SLen Brown value = 0; 1030b4f9fe12SLen Brown value2 = 0x0001; 1031893f3f62SAzael Avalos hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); 1032b4f9fe12SLen Brown 1033b4f9fe12SLen Brown *radio_state = value & HCI_WIRELESS_KILL_SWITCH; 1034b4f9fe12SLen Brown return hci_result; 1035b4f9fe12SLen Brown } 1036b4f9fe12SLen Brown 103719d337dfSJohannes Berg static int bt_rfkill_set_block(void *data, bool blocked) 1038b4f9fe12SLen Brown { 103919d337dfSJohannes Berg struct toshiba_acpi_dev *dev = data; 1040b4f9fe12SLen Brown u32 result1, result2; 1041b4f9fe12SLen Brown u32 value; 104219d337dfSJohannes Berg int err; 1043b4f9fe12SLen Brown bool radio_state; 1044b4f9fe12SLen Brown 104519d337dfSJohannes Berg value = (blocked == false); 1046b4f9fe12SLen Brown 1047b4f9fe12SLen Brown mutex_lock(&dev->mutex); 10481864bbc2SAzael Avalos if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) { 104932bcd5cbSSeth Forshee err = -EIO; 105019d337dfSJohannes Berg goto out; 1051b4f9fe12SLen Brown } 1052b4f9fe12SLen Brown 105319d337dfSJohannes Berg if (!radio_state) { 105419d337dfSJohannes Berg err = 0; 105519d337dfSJohannes Berg goto out; 105619d337dfSJohannes Berg } 105719d337dfSJohannes Berg 1058893f3f62SAzael Avalos result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER); 1059893f3f62SAzael Avalos result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH); 106019d337dfSJohannes Berg 10611864bbc2SAzael Avalos if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS) 106232bcd5cbSSeth Forshee err = -EIO; 106319d337dfSJohannes Berg else 106419d337dfSJohannes Berg err = 0; 106519d337dfSJohannes Berg out: 106619d337dfSJohannes Berg mutex_unlock(&dev->mutex); 106719d337dfSJohannes Berg return err; 106819d337dfSJohannes Berg } 106919d337dfSJohannes Berg 107019d337dfSJohannes Berg static void bt_rfkill_poll(struct rfkill *rfkill, void *data) 1071b4f9fe12SLen Brown { 1072b4f9fe12SLen Brown bool new_rfk_state; 1073b4f9fe12SLen Brown bool value; 1074b4f9fe12SLen Brown u32 hci_result; 107519d337dfSJohannes Berg struct toshiba_acpi_dev *dev = data; 107619d337dfSJohannes Berg 107719d337dfSJohannes Berg mutex_lock(&dev->mutex); 1078b4f9fe12SLen Brown 1079135740deSSeth Forshee hci_result = hci_get_radio_state(dev, &value); 10801864bbc2SAzael Avalos if (hci_result != TOS_SUCCESS) { 108119d337dfSJohannes Berg /* Can't do anything useful */ 108219d337dfSJohannes Berg mutex_unlock(&dev->mutex); 108382e7784fSJiri Slaby return; 108419d337dfSJohannes Berg } 1085b4f9fe12SLen Brown 1086b4f9fe12SLen Brown new_rfk_state = value; 1087b4f9fe12SLen Brown 1088b4f9fe12SLen Brown mutex_unlock(&dev->mutex); 1089b4f9fe12SLen Brown 109019d337dfSJohannes Berg if (rfkill_set_hw_state(rfkill, !new_rfk_state)) 109119d337dfSJohannes Berg bt_rfkill_set_block(data, true); 1092b4f9fe12SLen Brown } 109319d337dfSJohannes Berg 109419d337dfSJohannes Berg static const struct rfkill_ops toshiba_rfk_ops = { 109519d337dfSJohannes Berg .set_block = bt_rfkill_set_block, 109619d337dfSJohannes Berg .poll = bt_rfkill_poll, 109719d337dfSJohannes Berg }; 1098b4f9fe12SLen Brown 1099121b7b0dSAkio Idehara static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) 1100121b7b0dSAkio Idehara { 1101121b7b0dSAkio Idehara u32 hci_result; 1102121b7b0dSAkio Idehara u32 status; 1103121b7b0dSAkio Idehara 1104893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status); 1105121b7b0dSAkio Idehara *enabled = !status; 11061864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1107121b7b0dSAkio Idehara } 1108121b7b0dSAkio Idehara 1109121b7b0dSAkio Idehara static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) 1110121b7b0dSAkio Idehara { 1111121b7b0dSAkio Idehara u32 hci_result; 1112121b7b0dSAkio Idehara u32 value = !enable; 1113121b7b0dSAkio Idehara 1114893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value); 11151864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1116121b7b0dSAkio Idehara } 1117121b7b0dSAkio Idehara 1118b4f9fe12SLen Brown static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; 1119b4f9fe12SLen Brown 112062cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1121b4f9fe12SLen Brown { 1122b4f9fe12SLen Brown u32 hci_result; 1123b4f9fe12SLen Brown u32 value; 1124121b7b0dSAkio Idehara int brightness = 0; 1125121b7b0dSAkio Idehara 1126121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1127121b7b0dSAkio Idehara bool enabled; 1128121b7b0dSAkio Idehara int ret = get_tr_backlight_status(dev, &enabled); 1129121b7b0dSAkio Idehara if (ret) 1130121b7b0dSAkio Idehara return ret; 1131121b7b0dSAkio Idehara if (enabled) 1132121b7b0dSAkio Idehara return 0; 1133121b7b0dSAkio Idehara brightness++; 1134121b7b0dSAkio Idehara } 1135b4f9fe12SLen Brown 1136893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value); 11371864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1138121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 113932bcd5cbSSeth Forshee 114032bcd5cbSSeth Forshee return -EIO; 1141b4f9fe12SLen Brown } 1142b4f9fe12SLen Brown 114362cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 114462cce752SSeth Forshee { 114562cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 114662cce752SSeth Forshee return __get_lcd_brightness(dev); 114762cce752SSeth Forshee } 114862cce752SSeth Forshee 1149936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1150b4f9fe12SLen Brown { 1151135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1152135740deSSeth Forshee int value; 1153121b7b0dSAkio Idehara int levels; 1154b4f9fe12SLen Brown 1155135740deSSeth Forshee if (!dev->backlight_dev) 1156135740deSSeth Forshee return -ENODEV; 1157135740deSSeth Forshee 1158121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 115962cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1160b4f9fe12SLen Brown if (value >= 0) { 1161936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1162121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 116332bcd5cbSSeth Forshee return 0; 1164b4f9fe12SLen Brown } 1165b4f9fe12SLen Brown 116632bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 116732bcd5cbSSeth Forshee return -EIO; 1168936c8bcdSAlexey Dobriyan } 1169936c8bcdSAlexey Dobriyan 1170936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1171936c8bcdSAlexey Dobriyan { 1172d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1173b4f9fe12SLen Brown } 1174b4f9fe12SLen Brown 117562cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1176b4f9fe12SLen Brown { 1177a39f46dfSAzael Avalos u32 hci_result; 1178b4f9fe12SLen Brown 1179121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1180121b7b0dSAkio Idehara bool enable = !value; 1181121b7b0dSAkio Idehara int ret = set_tr_backlight_status(dev, enable); 1182121b7b0dSAkio Idehara if (ret) 1183121b7b0dSAkio Idehara return ret; 1184121b7b0dSAkio Idehara if (value) 1185121b7b0dSAkio Idehara value--; 1186121b7b0dSAkio Idehara } 1187121b7b0dSAkio Idehara 1188a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1189a39f46dfSAzael Avalos hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value); 1190a39f46dfSAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1191b4f9fe12SLen Brown } 1192b4f9fe12SLen Brown 1193b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1194b4f9fe12SLen Brown { 1195135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 119662cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1197b4f9fe12SLen Brown } 1198b4f9fe12SLen Brown 1199936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1200936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1201b4f9fe12SLen Brown { 1202d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1203936c8bcdSAlexey Dobriyan char cmd[42]; 1204936c8bcdSAlexey Dobriyan size_t len; 1205b4f9fe12SLen Brown int value; 1206b4f9fe12SLen Brown int ret; 1207121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1208b4f9fe12SLen Brown 1209936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1210936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1211936c8bcdSAlexey Dobriyan return -EFAULT; 1212936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1213936c8bcdSAlexey Dobriyan 1214936c8bcdSAlexey Dobriyan if (sscanf(cmd, " brightness : %i", &value) == 1 && 1215121b7b0dSAkio Idehara value >= 0 && value < levels) { 121662cce752SSeth Forshee ret = set_lcd_brightness(dev, value); 1217b4f9fe12SLen Brown if (ret == 0) 1218b4f9fe12SLen Brown ret = count; 1219b4f9fe12SLen Brown } else { 1220b4f9fe12SLen Brown ret = -EINVAL; 1221b4f9fe12SLen Brown } 1222b4f9fe12SLen Brown return ret; 1223b4f9fe12SLen Brown } 1224b4f9fe12SLen Brown 1225936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1226936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1227936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1228936c8bcdSAlexey Dobriyan .read = seq_read, 1229936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1230936c8bcdSAlexey Dobriyan .release = single_release, 1231936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1232936c8bcdSAlexey Dobriyan }; 1233936c8bcdSAlexey Dobriyan 123436d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 123536d03f93SSeth Forshee { 123636d03f93SSeth Forshee u32 hci_result; 123736d03f93SSeth Forshee 1238893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_VIDEO_OUT, status); 12391864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 124036d03f93SSeth Forshee } 124136d03f93SSeth Forshee 1242936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1243b4f9fe12SLen Brown { 1244135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1245b4f9fe12SLen Brown u32 value; 124636d03f93SSeth Forshee int ret; 1247b4f9fe12SLen Brown 124836d03f93SSeth Forshee ret = get_video_status(dev, &value); 124936d03f93SSeth Forshee if (!ret) { 1250b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1251b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1252b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1253936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1254936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1255936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1256b4f9fe12SLen Brown } 1257b4f9fe12SLen Brown 125836d03f93SSeth Forshee return ret; 1259b4f9fe12SLen Brown } 1260b4f9fe12SLen Brown 1261936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1262b4f9fe12SLen Brown { 1263d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1264936c8bcdSAlexey Dobriyan } 1265936c8bcdSAlexey Dobriyan 1266936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1267936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1268936c8bcdSAlexey Dobriyan { 1269d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1270936c8bcdSAlexey Dobriyan char *cmd, *buffer; 127136d03f93SSeth Forshee int ret; 1272b4f9fe12SLen Brown int value; 1273b4f9fe12SLen Brown int remain = count; 1274b4f9fe12SLen Brown int lcd_out = -1; 1275b4f9fe12SLen Brown int crt_out = -1; 1276b4f9fe12SLen Brown int tv_out = -1; 1277b4f9fe12SLen Brown u32 video_out; 1278b4f9fe12SLen Brown 1279936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1280936c8bcdSAlexey Dobriyan if (!cmd) 1281936c8bcdSAlexey Dobriyan return -ENOMEM; 1282936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1283936c8bcdSAlexey Dobriyan kfree(cmd); 1284936c8bcdSAlexey Dobriyan return -EFAULT; 1285936c8bcdSAlexey Dobriyan } 1286936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1287936c8bcdSAlexey Dobriyan 1288936c8bcdSAlexey Dobriyan buffer = cmd; 1289936c8bcdSAlexey Dobriyan 1290b4f9fe12SLen Brown /* scan expression. Multiple expressions may be delimited with ; 1291b4f9fe12SLen Brown * 1292b4f9fe12SLen Brown * NOTE: to keep scanning simple, invalid fields are ignored 1293b4f9fe12SLen Brown */ 1294b4f9fe12SLen Brown while (remain) { 1295b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1296b4f9fe12SLen Brown lcd_out = value & 1; 1297b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1298b4f9fe12SLen Brown crt_out = value & 1; 1299b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1300b4f9fe12SLen Brown tv_out = value & 1; 1301b4f9fe12SLen Brown /* advance to one character past the next ; */ 1302b4f9fe12SLen Brown do { 1303b4f9fe12SLen Brown ++buffer; 1304b4f9fe12SLen Brown --remain; 1305b4f9fe12SLen Brown } 1306b4f9fe12SLen Brown while (remain && *(buffer - 1) != ';'); 1307b4f9fe12SLen Brown } 1308b4f9fe12SLen Brown 1309936c8bcdSAlexey Dobriyan kfree(cmd); 1310936c8bcdSAlexey Dobriyan 131136d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 131236d03f93SSeth Forshee if (!ret) { 1313b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1314b4f9fe12SLen Brown if (lcd_out != -1) 1315b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1316b4f9fe12SLen Brown if (crt_out != -1) 1317b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1318b4f9fe12SLen Brown if (tv_out != -1) 1319b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1320b4f9fe12SLen Brown /* To avoid unnecessary video disruption, only write the new 1321b4f9fe12SLen Brown * video setting if something changed. */ 1322b4f9fe12SLen Brown if (new_video_out != video_out) 132332bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1324b4f9fe12SLen Brown } 1325b4f9fe12SLen Brown 132632bcd5cbSSeth Forshee return ret ? ret : count; 1327b4f9fe12SLen Brown } 1328b4f9fe12SLen Brown 1329936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1330936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1331936c8bcdSAlexey Dobriyan .open = video_proc_open, 1332936c8bcdSAlexey Dobriyan .read = seq_read, 1333936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1334936c8bcdSAlexey Dobriyan .release = single_release, 1335936c8bcdSAlexey Dobriyan .write = video_proc_write, 1336936c8bcdSAlexey Dobriyan }; 1337936c8bcdSAlexey Dobriyan 133836d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 133936d03f93SSeth Forshee { 134036d03f93SSeth Forshee u32 hci_result; 134136d03f93SSeth Forshee 1342893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_FAN, status); 13431864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 134436d03f93SSeth Forshee } 134536d03f93SSeth Forshee 1346936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1347b4f9fe12SLen Brown { 1348135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 134936d03f93SSeth Forshee int ret; 1350b4f9fe12SLen Brown u32 value; 1351b4f9fe12SLen Brown 135236d03f93SSeth Forshee ret = get_fan_status(dev, &value); 135336d03f93SSeth Forshee if (!ret) { 1354936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1355135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1356b4f9fe12SLen Brown } 1357b4f9fe12SLen Brown 135836d03f93SSeth Forshee return ret; 1359b4f9fe12SLen Brown } 1360b4f9fe12SLen Brown 1361936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1362b4f9fe12SLen Brown { 1363d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1364936c8bcdSAlexey Dobriyan } 1365936c8bcdSAlexey Dobriyan 1366936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1367936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1368936c8bcdSAlexey Dobriyan { 1369d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1370936c8bcdSAlexey Dobriyan char cmd[42]; 1371936c8bcdSAlexey Dobriyan size_t len; 1372b4f9fe12SLen Brown int value; 1373b4f9fe12SLen Brown u32 hci_result; 1374b4f9fe12SLen Brown 1375936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1376936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1377936c8bcdSAlexey Dobriyan return -EFAULT; 1378936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1379936c8bcdSAlexey Dobriyan 1380936c8bcdSAlexey Dobriyan if (sscanf(cmd, " force_on : %i", &value) == 1 && 1381b4f9fe12SLen Brown value >= 0 && value <= 1) { 1382893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_FAN, value); 13831864bbc2SAzael Avalos if (hci_result != TOS_SUCCESS) 138432bcd5cbSSeth Forshee return -EIO; 1385b4f9fe12SLen Brown else 1386135740deSSeth Forshee dev->force_fan = value; 1387b4f9fe12SLen Brown } else { 1388b4f9fe12SLen Brown return -EINVAL; 1389b4f9fe12SLen Brown } 1390b4f9fe12SLen Brown 1391b4f9fe12SLen Brown return count; 1392b4f9fe12SLen Brown } 1393b4f9fe12SLen Brown 1394936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1395936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1396936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1397936c8bcdSAlexey Dobriyan .read = seq_read, 1398936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1399936c8bcdSAlexey Dobriyan .release = single_release, 1400936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1401936c8bcdSAlexey Dobriyan }; 1402936c8bcdSAlexey Dobriyan 1403936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1404b4f9fe12SLen Brown { 1405135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1406b4f9fe12SLen Brown u32 hci_result; 1407b4f9fe12SLen Brown u32 value; 1408b4f9fe12SLen Brown 140911948b93SSeth Forshee if (!dev->key_event_valid && dev->system_event_supported) { 1410893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 14111864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) { 1412135740deSSeth Forshee dev->key_event_valid = 1; 1413135740deSSeth Forshee dev->last_key_event = value; 14141864bbc2SAzael Avalos } else if (hci_result == TOS_FIFO_EMPTY) { 1415b4f9fe12SLen Brown /* better luck next time */ 14161864bbc2SAzael Avalos } else if (hci_result == TOS_NOT_SUPPORTED) { 1417b4f9fe12SLen Brown /* This is a workaround for an unresolved issue on 1418b4f9fe12SLen Brown * some machines where system events sporadically 1419b4f9fe12SLen Brown * become disabled. */ 1420893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); 14217e33460dSJoe Perches pr_notice("Re-enabled hotkeys\n"); 1422b4f9fe12SLen Brown } else { 14237e33460dSJoe Perches pr_err("Error reading hotkey status\n"); 142432bcd5cbSSeth Forshee return -EIO; 1425b4f9fe12SLen Brown } 1426b4f9fe12SLen Brown } 1427b4f9fe12SLen Brown 1428135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1429135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 1430936c8bcdSAlexey Dobriyan return 0; 1431b4f9fe12SLen Brown } 1432b4f9fe12SLen Brown 1433936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1434b4f9fe12SLen Brown { 1435d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1436936c8bcdSAlexey Dobriyan } 1437936c8bcdSAlexey Dobriyan 1438936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1439936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1440936c8bcdSAlexey Dobriyan { 1441d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1442936c8bcdSAlexey Dobriyan char cmd[42]; 1443936c8bcdSAlexey Dobriyan size_t len; 1444b4f9fe12SLen Brown int value; 1445b4f9fe12SLen Brown 1446936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1447936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1448936c8bcdSAlexey Dobriyan return -EFAULT; 1449936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1450936c8bcdSAlexey Dobriyan 1451936c8bcdSAlexey Dobriyan if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) { 1452135740deSSeth Forshee dev->key_event_valid = 0; 1453b4f9fe12SLen Brown } else { 1454b4f9fe12SLen Brown return -EINVAL; 1455b4f9fe12SLen Brown } 1456b4f9fe12SLen Brown 1457b4f9fe12SLen Brown return count; 1458b4f9fe12SLen Brown } 1459b4f9fe12SLen Brown 1460936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1461936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1462936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1463936c8bcdSAlexey Dobriyan .read = seq_read, 1464936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1465936c8bcdSAlexey Dobriyan .release = single_release, 1466936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1467936c8bcdSAlexey Dobriyan }; 1468936c8bcdSAlexey Dobriyan 1469936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1470b4f9fe12SLen Brown { 1471936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1472936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1473936c8bcdSAlexey Dobriyan return 0; 1474b4f9fe12SLen Brown } 1475b4f9fe12SLen Brown 1476936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1477936c8bcdSAlexey Dobriyan { 1478d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1479936c8bcdSAlexey Dobriyan } 1480936c8bcdSAlexey Dobriyan 1481936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1482936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1483936c8bcdSAlexey Dobriyan .open = version_proc_open, 1484936c8bcdSAlexey Dobriyan .read = seq_read, 1485936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1486936c8bcdSAlexey Dobriyan .release = single_release, 1487936c8bcdSAlexey Dobriyan }; 1488936c8bcdSAlexey Dobriyan 1489b4f9fe12SLen Brown /* proc and module init 1490b4f9fe12SLen Brown */ 1491b4f9fe12SLen Brown 1492b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1493b4f9fe12SLen Brown 1494b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1495b4f9fe12SLen Brown { 149636d03f93SSeth Forshee if (dev->backlight_dev) 1497135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1498135740deSSeth Forshee &lcd_proc_fops, dev); 149936d03f93SSeth Forshee if (dev->video_supported) 1500135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1501135740deSSeth Forshee &video_proc_fops, dev); 150236d03f93SSeth Forshee if (dev->fan_supported) 1503135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1504135740deSSeth Forshee &fan_proc_fops, dev); 150536d03f93SSeth Forshee if (dev->hotkey_dev) 1506135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1507135740deSSeth Forshee &keys_proc_fops, dev); 1508135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1509135740deSSeth Forshee &version_proc_fops, dev); 1510b4f9fe12SLen Brown } 1511b4f9fe12SLen Brown 151236d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1513b4f9fe12SLen Brown { 151436d03f93SSeth Forshee if (dev->backlight_dev) 1515936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 151636d03f93SSeth Forshee if (dev->video_supported) 1517936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 151836d03f93SSeth Forshee if (dev->fan_supported) 1519936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 152036d03f93SSeth Forshee if (dev->hotkey_dev) 1521936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1522936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1523b4f9fe12SLen Brown } 1524b4f9fe12SLen Brown 1525acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1526121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 152762cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1528b4f9fe12SLen Brown .update_status = set_lcd_status, 1529b4f9fe12SLen Brown }; 1530b4f9fe12SLen Brown 1531360f0f39SAzael Avalos /* 1532360f0f39SAzael Avalos * Sysfs files 1533360f0f39SAzael Avalos */ 153493f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, 153593f8c16dSAzael Avalos struct device_attribute *attr, 153693f8c16dSAzael Avalos const char *buf, size_t count); 153793f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_mode_show(struct device *dev, 153893f8c16dSAzael Avalos struct device_attribute *attr, 153993f8c16dSAzael Avalos char *buf); 154093f8c16dSAzael Avalos static ssize_t toshiba_kbd_type_show(struct device *dev, 154193f8c16dSAzael Avalos struct device_attribute *attr, 154293f8c16dSAzael Avalos char *buf); 154393f8c16dSAzael Avalos static ssize_t toshiba_available_kbd_modes_show(struct device *dev, 154493f8c16dSAzael Avalos struct device_attribute *attr, 154593f8c16dSAzael Avalos char *buf); 154693f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev, 154793f8c16dSAzael Avalos struct device_attribute *attr, 154893f8c16dSAzael Avalos const char *buf, size_t count); 154993f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev, 155093f8c16dSAzael Avalos struct device_attribute *attr, 155193f8c16dSAzael Avalos char *buf); 155293f8c16dSAzael Avalos static ssize_t toshiba_touchpad_store(struct device *dev, 155393f8c16dSAzael Avalos struct device_attribute *attr, 155493f8c16dSAzael Avalos const char *buf, size_t count); 155593f8c16dSAzael Avalos static ssize_t toshiba_touchpad_show(struct device *dev, 155693f8c16dSAzael Avalos struct device_attribute *attr, 155793f8c16dSAzael Avalos char *buf); 155893f8c16dSAzael Avalos static ssize_t toshiba_position_show(struct device *dev, 155993f8c16dSAzael Avalos struct device_attribute *attr, 156093f8c16dSAzael Avalos char *buf); 1561e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_show(struct device *dev, 1562e26ffe51SAzael Avalos struct device_attribute *attr, 1563e26ffe51SAzael Avalos char *buf); 1564e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_store(struct device *dev, 1565e26ffe51SAzael Avalos struct device_attribute *attr, 1566e26ffe51SAzael Avalos const char *buf, size_t count); 1567182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1568182bcaa5SAzael Avalos struct device_attribute *attr, 1569182bcaa5SAzael Avalos char *buf); 1570182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 1571182bcaa5SAzael Avalos struct device_attribute *attr, 1572182bcaa5SAzael Avalos const char *buf, size_t count); 1573bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_show(struct device *dev, 1574bb3fe01fSAzael Avalos struct device_attribute *attr, 1575bb3fe01fSAzael Avalos char *buf); 1576bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_store(struct device *dev, 1577bb3fe01fSAzael Avalos struct device_attribute *attr, 1578bb3fe01fSAzael Avalos const char *buf, size_t count); 1579172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_show(struct device *dev, 1580172ce0a9SAzael Avalos struct device_attribute *attr, 1581172ce0a9SAzael Avalos char *buf); 1582172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_store(struct device *dev, 1583172ce0a9SAzael Avalos struct device_attribute *attr, 1584172ce0a9SAzael Avalos const char *buf, size_t count); 158593f8c16dSAzael Avalos 158693f8c16dSAzael Avalos static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR, 158793f8c16dSAzael Avalos toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store); 158893f8c16dSAzael Avalos static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL); 158993f8c16dSAzael Avalos static DEVICE_ATTR(available_kbd_modes, S_IRUGO, 159093f8c16dSAzael Avalos toshiba_available_kbd_modes_show, NULL); 159193f8c16dSAzael Avalos static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR, 159293f8c16dSAzael Avalos toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store); 159393f8c16dSAzael Avalos static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR, 159493f8c16dSAzael Avalos toshiba_touchpad_show, toshiba_touchpad_store); 159593f8c16dSAzael Avalos static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL); 1596e26ffe51SAzael Avalos static DEVICE_ATTR(usb_sleep_charge, S_IRUGO | S_IWUSR, 1597e26ffe51SAzael Avalos toshiba_usb_sleep_charge_show, 1598e26ffe51SAzael Avalos toshiba_usb_sleep_charge_store); 1599182bcaa5SAzael Avalos static DEVICE_ATTR(sleep_functions_on_battery, S_IRUGO | S_IWUSR, 1600182bcaa5SAzael Avalos sleep_functions_on_battery_show, 1601182bcaa5SAzael Avalos sleep_functions_on_battery_store); 1602bb3fe01fSAzael Avalos static DEVICE_ATTR(usb_rapid_charge, S_IRUGO | S_IWUSR, 1603bb3fe01fSAzael Avalos toshiba_usb_rapid_charge_show, 1604bb3fe01fSAzael Avalos toshiba_usb_rapid_charge_store); 1605172ce0a9SAzael Avalos static DEVICE_ATTR(usb_sleep_music, S_IRUGO | S_IWUSR, 1606172ce0a9SAzael Avalos toshiba_usb_sleep_music_show, 1607172ce0a9SAzael Avalos toshiba_usb_sleep_music_store); 160893f8c16dSAzael Avalos 160993f8c16dSAzael Avalos static struct attribute *toshiba_attributes[] = { 161093f8c16dSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 161193f8c16dSAzael Avalos &dev_attr_kbd_type.attr, 161293f8c16dSAzael Avalos &dev_attr_available_kbd_modes.attr, 161393f8c16dSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 161493f8c16dSAzael Avalos &dev_attr_touchpad.attr, 161593f8c16dSAzael Avalos &dev_attr_position.attr, 1616e26ffe51SAzael Avalos &dev_attr_usb_sleep_charge.attr, 1617182bcaa5SAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 1618bb3fe01fSAzael Avalos &dev_attr_usb_rapid_charge.attr, 1619172ce0a9SAzael Avalos &dev_attr_usb_sleep_music.attr, 162093f8c16dSAzael Avalos NULL, 162193f8c16dSAzael Avalos }; 162293f8c16dSAzael Avalos 162393f8c16dSAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *, 162493f8c16dSAzael Avalos struct attribute *, int); 162593f8c16dSAzael Avalos 162693f8c16dSAzael Avalos static struct attribute_group toshiba_attr_group = { 162793f8c16dSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 162893f8c16dSAzael Avalos .attrs = toshiba_attributes, 162993f8c16dSAzael Avalos }; 1630360f0f39SAzael Avalos 1631360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, 1632360f0f39SAzael Avalos struct device_attribute *attr, 1633360f0f39SAzael Avalos const char *buf, size_t count) 1634360f0f39SAzael Avalos { 1635360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1636aeaac098SDan Carpenter int mode; 1637aeaac098SDan Carpenter int time; 1638aeaac098SDan Carpenter int ret; 1639360f0f39SAzael Avalos 1640aeaac098SDan Carpenter 1641aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1642aeaac098SDan Carpenter if (ret) 1643aeaac098SDan Carpenter return ret; 164493f8c16dSAzael Avalos 164593f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 164693f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 164793f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1648aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1649360f0f39SAzael Avalos return -EINVAL; 165093f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 165193f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 165293f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 165393f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 165493f8c16dSAzael Avalos return -EINVAL; 165593f8c16dSAzael Avalos } 1656360f0f39SAzael Avalos 1657360f0f39SAzael Avalos /* Set the Keyboard Backlight Mode where: 1658360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1659360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 166093f8c16dSAzael Avalos * ON - KBD backlight is always on 166193f8c16dSAzael Avalos * OFF - KBD backlight is always off 1662360f0f39SAzael Avalos */ 166393f8c16dSAzael Avalos 166493f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1665aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 166693f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1667360f0f39SAzael Avalos time = toshiba->kbd_time << HCI_MISC_SHIFT; 166893f8c16dSAzael Avalos 166993f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 167093f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 167193f8c16dSAzael Avalos /* Type 1 requires the current mode */ 167293f8c16dSAzael Avalos time |= toshiba->kbd_mode; 167393f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 167493f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 167593f8c16dSAzael Avalos time |= mode; 167693f8c16dSAzael Avalos } 167793f8c16dSAzael Avalos 1678aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1679aeaac098SDan Carpenter if (ret) 1680aeaac098SDan Carpenter return ret; 168193f8c16dSAzael Avalos 1682360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1683360f0f39SAzael Avalos } 1684360f0f39SAzael Avalos 1685360f0f39SAzael Avalos return count; 1686360f0f39SAzael Avalos } 1687360f0f39SAzael Avalos 1688360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_mode_show(struct device *dev, 1689360f0f39SAzael Avalos struct device_attribute *attr, 1690360f0f39SAzael Avalos char *buf) 1691360f0f39SAzael Avalos { 1692360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1693360f0f39SAzael Avalos u32 time; 1694360f0f39SAzael Avalos 1695360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1696360f0f39SAzael Avalos return -EIO; 1697360f0f39SAzael Avalos 169893f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 169993f8c16dSAzael Avalos } 170093f8c16dSAzael Avalos 170193f8c16dSAzael Avalos static ssize_t toshiba_kbd_type_show(struct device *dev, 170293f8c16dSAzael Avalos struct device_attribute *attr, 170393f8c16dSAzael Avalos char *buf) 170493f8c16dSAzael Avalos { 170593f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 170693f8c16dSAzael Avalos 170793f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 170893f8c16dSAzael Avalos } 170993f8c16dSAzael Avalos 171093f8c16dSAzael Avalos static ssize_t toshiba_available_kbd_modes_show(struct device *dev, 171193f8c16dSAzael Avalos struct device_attribute *attr, 171293f8c16dSAzael Avalos char *buf) 171393f8c16dSAzael Avalos { 171493f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 171593f8c16dSAzael Avalos 171693f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 171793f8c16dSAzael Avalos return sprintf(buf, "%x %x\n", 171893f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 171993f8c16dSAzael Avalos 172093f8c16dSAzael Avalos return sprintf(buf, "%x %x %x\n", 172193f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1722360f0f39SAzael Avalos } 1723360f0f39SAzael Avalos 1724360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev, 1725360f0f39SAzael Avalos struct device_attribute *attr, 1726360f0f39SAzael Avalos const char *buf, size_t count) 1727360f0f39SAzael Avalos { 1728360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1729eabde0faSAzael Avalos int time; 1730eabde0faSAzael Avalos int ret; 1731360f0f39SAzael Avalos 1732eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1733eabde0faSAzael Avalos if (ret) 1734eabde0faSAzael Avalos return ret; 1735eabde0faSAzael Avalos 1736eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1737eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1738eabde0faSAzael Avalos if (time < 0 || time > 60) 1739360f0f39SAzael Avalos return -EINVAL; 1740eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1741eabde0faSAzael Avalos if (time < 1 || time > 60) 1742eabde0faSAzael Avalos return -EINVAL; 1743eabde0faSAzael Avalos } 1744360f0f39SAzael Avalos 1745eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1746eabde0faSAzael Avalos 1747eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1748eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1749eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1750360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1751eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1752eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1753eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1754eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1755eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1756eabde0faSAzael Avalos 1757eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1758eabde0faSAzael Avalos if (ret) 1759eabde0faSAzael Avalos return ret; 1760eabde0faSAzael Avalos 1761360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1762360f0f39SAzael Avalos } 1763360f0f39SAzael Avalos 1764360f0f39SAzael Avalos return count; 1765360f0f39SAzael Avalos } 1766360f0f39SAzael Avalos 1767360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev, 1768360f0f39SAzael Avalos struct device_attribute *attr, 1769360f0f39SAzael Avalos char *buf) 1770360f0f39SAzael Avalos { 1771360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1772360f0f39SAzael Avalos u32 time; 1773360f0f39SAzael Avalos 1774360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1775360f0f39SAzael Avalos return -EIO; 1776360f0f39SAzael Avalos 1777360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1778360f0f39SAzael Avalos } 1779360f0f39SAzael Avalos 17809d8658acSAzael Avalos static ssize_t toshiba_touchpad_store(struct device *dev, 17819d8658acSAzael Avalos struct device_attribute *attr, 17829d8658acSAzael Avalos const char *buf, size_t count) 17839d8658acSAzael Avalos { 17849d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17859d8658acSAzael Avalos int state; 1786c8a41669SAzael Avalos int ret; 17879d8658acSAzael Avalos 17889d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1789c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1790c8a41669SAzael Avalos if (ret) 1791c8a41669SAzael Avalos return ret; 1792c8a41669SAzael Avalos if (state != 0 && state != 1) 1793c8a41669SAzael Avalos return -EINVAL; 1794c8a41669SAzael Avalos 1795c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1796c8a41669SAzael Avalos if (ret) 1797c8a41669SAzael Avalos return ret; 17989d8658acSAzael Avalos 17999d8658acSAzael Avalos return count; 18009d8658acSAzael Avalos } 18019d8658acSAzael Avalos 18029d8658acSAzael Avalos static ssize_t toshiba_touchpad_show(struct device *dev, 18039d8658acSAzael Avalos struct device_attribute *attr, char *buf) 18049d8658acSAzael Avalos { 18059d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18069d8658acSAzael Avalos u32 state; 18079d8658acSAzael Avalos int ret; 18089d8658acSAzael Avalos 18099d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 18109d8658acSAzael Avalos if (ret < 0) 18119d8658acSAzael Avalos return ret; 18129d8658acSAzael Avalos 18139d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 18149d8658acSAzael Avalos } 18159d8658acSAzael Avalos 18165a2813e9SAzael Avalos static ssize_t toshiba_position_show(struct device *dev, 18175a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 18185a2813e9SAzael Avalos { 18195a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18205a2813e9SAzael Avalos u32 xyval, zval, tmp; 18215a2813e9SAzael Avalos u16 x, y, z; 18225a2813e9SAzael Avalos int ret; 18235a2813e9SAzael Avalos 18245a2813e9SAzael Avalos xyval = zval = 0; 18255a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 18265a2813e9SAzael Avalos if (ret < 0) 18275a2813e9SAzael Avalos return ret; 18285a2813e9SAzael Avalos 18295a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 18305a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 18315a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 18325a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 18335a2813e9SAzael Avalos 18345a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 18355a2813e9SAzael Avalos } 18365a2813e9SAzael Avalos 1837e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_show(struct device *dev, 1838e26ffe51SAzael Avalos struct device_attribute *attr, 1839e26ffe51SAzael Avalos char *buf) 1840e26ffe51SAzael Avalos { 1841e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1842e26ffe51SAzael Avalos u32 mode; 1843e26ffe51SAzael Avalos int ret; 1844e26ffe51SAzael Avalos 1845e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1846e26ffe51SAzael Avalos if (ret < 0) 1847e26ffe51SAzael Avalos return ret; 1848e26ffe51SAzael Avalos 1849e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1850e26ffe51SAzael Avalos } 1851e26ffe51SAzael Avalos 1852e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_store(struct device *dev, 1853e26ffe51SAzael Avalos struct device_attribute *attr, 1854e26ffe51SAzael Avalos const char *buf, size_t count) 1855e26ffe51SAzael Avalos { 1856e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1857e26ffe51SAzael Avalos u32 mode; 1858e26ffe51SAzael Avalos int state; 1859e26ffe51SAzael Avalos int ret; 1860e26ffe51SAzael Avalos 1861e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 1862e26ffe51SAzael Avalos if (ret) 1863e26ffe51SAzael Avalos return ret; 1864e26ffe51SAzael Avalos /* Check for supported values, where: 1865e26ffe51SAzael Avalos * 0 - Disabled 1866e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 1867e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 1868e26ffe51SAzael Avalos */ 1869e26ffe51SAzael Avalos if (state != 0 && state != 1 && state != 2) 1870e26ffe51SAzael Avalos return -EINVAL; 1871e26ffe51SAzael Avalos 1872e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 1873e26ffe51SAzael Avalos if (state == 0) 1874e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_DISABLED; 1875e26ffe51SAzael Avalos else if (state == 1) 1876e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_ALTERNATE; 1877e26ffe51SAzael Avalos else if (state == 2) 1878e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_AUTO; 1879e26ffe51SAzael Avalos 1880e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 1881e26ffe51SAzael Avalos if (ret) 1882e26ffe51SAzael Avalos return ret; 1883e26ffe51SAzael Avalos 1884e26ffe51SAzael Avalos return count; 1885e26ffe51SAzael Avalos } 1886e26ffe51SAzael Avalos 1887182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1888182bcaa5SAzael Avalos struct device_attribute *attr, 1889182bcaa5SAzael Avalos char *buf) 1890182bcaa5SAzael Avalos { 1891182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1892182bcaa5SAzael Avalos u32 state; 1893182bcaa5SAzael Avalos int bat_lvl; 1894182bcaa5SAzael Avalos int status; 1895182bcaa5SAzael Avalos int ret; 1896182bcaa5SAzael Avalos int tmp; 1897182bcaa5SAzael Avalos 1898182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 1899182bcaa5SAzael Avalos if (ret < 0) 1900182bcaa5SAzael Avalos return ret; 1901182bcaa5SAzael Avalos 1902182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 1903182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 1904182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 1905182bcaa5SAzael Avalos /* Determine the battery level set */ 1906182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 1907182bcaa5SAzael Avalos 1908182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 1909182bcaa5SAzael Avalos } 1910182bcaa5SAzael Avalos 1911182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 1912182bcaa5SAzael Avalos struct device_attribute *attr, 1913182bcaa5SAzael Avalos const char *buf, size_t count) 1914182bcaa5SAzael Avalos { 1915182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1916182bcaa5SAzael Avalos u32 status; 1917182bcaa5SAzael Avalos int value; 1918182bcaa5SAzael Avalos int ret; 1919182bcaa5SAzael Avalos int tmp; 1920182bcaa5SAzael Avalos 1921182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 1922182bcaa5SAzael Avalos if (ret) 1923182bcaa5SAzael Avalos return ret; 1924182bcaa5SAzael Avalos 1925182bcaa5SAzael Avalos /* Set the status of the function: 1926182bcaa5SAzael Avalos * 0 - Disabled 1927182bcaa5SAzael Avalos * 1-100 - Enabled 1928182bcaa5SAzael Avalos */ 1929182bcaa5SAzael Avalos if (value < 0 || value > 100) 1930182bcaa5SAzael Avalos return -EINVAL; 1931182bcaa5SAzael Avalos 1932182bcaa5SAzael Avalos if (value == 0) { 1933182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 1934182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 1935182bcaa5SAzael Avalos } else { 1936182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 1937182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 1938182bcaa5SAzael Avalos } 1939182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 1940182bcaa5SAzael Avalos if (ret < 0) 1941182bcaa5SAzael Avalos return ret; 1942182bcaa5SAzael Avalos 1943182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 1944182bcaa5SAzael Avalos 1945182bcaa5SAzael Avalos return count; 1946182bcaa5SAzael Avalos } 1947182bcaa5SAzael Avalos 1948bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_show(struct device *dev, 1949bb3fe01fSAzael Avalos struct device_attribute *attr, 1950bb3fe01fSAzael Avalos char *buf) 1951bb3fe01fSAzael Avalos { 1952bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1953bb3fe01fSAzael Avalos u32 state; 1954bb3fe01fSAzael Avalos int ret; 1955bb3fe01fSAzael Avalos 1956bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 1957bb3fe01fSAzael Avalos if (ret < 0) 1958bb3fe01fSAzael Avalos return ret; 1959bb3fe01fSAzael Avalos 1960bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 1961bb3fe01fSAzael Avalos } 1962bb3fe01fSAzael Avalos 1963bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_store(struct device *dev, 1964bb3fe01fSAzael Avalos struct device_attribute *attr, 1965bb3fe01fSAzael Avalos const char *buf, size_t count) 1966bb3fe01fSAzael Avalos { 1967bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1968bb3fe01fSAzael Avalos int state; 1969bb3fe01fSAzael Avalos int ret; 1970bb3fe01fSAzael Avalos 1971bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 1972bb3fe01fSAzael Avalos if (ret) 1973bb3fe01fSAzael Avalos return ret; 1974bb3fe01fSAzael Avalos if (state != 0 && state != 1) 1975bb3fe01fSAzael Avalos return -EINVAL; 1976bb3fe01fSAzael Avalos 1977bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 1978bb3fe01fSAzael Avalos if (ret) 1979bb3fe01fSAzael Avalos return ret; 1980bb3fe01fSAzael Avalos 1981bb3fe01fSAzael Avalos return count; 1982bb3fe01fSAzael Avalos } 1983bb3fe01fSAzael Avalos 1984172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_show(struct device *dev, 1985172ce0a9SAzael Avalos struct device_attribute *attr, 1986172ce0a9SAzael Avalos char *buf) 1987172ce0a9SAzael Avalos { 1988172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1989172ce0a9SAzael Avalos u32 state; 1990172ce0a9SAzael Avalos int ret; 1991172ce0a9SAzael Avalos 1992172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 1993172ce0a9SAzael Avalos if (ret < 0) 1994172ce0a9SAzael Avalos return ret; 1995172ce0a9SAzael Avalos 1996172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 1997172ce0a9SAzael Avalos } 1998172ce0a9SAzael Avalos 1999172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_store(struct device *dev, 2000172ce0a9SAzael Avalos struct device_attribute *attr, 2001172ce0a9SAzael Avalos const char *buf, size_t count) 2002172ce0a9SAzael Avalos { 2003172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2004172ce0a9SAzael Avalos int state; 2005172ce0a9SAzael Avalos int ret; 2006172ce0a9SAzael Avalos 2007172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2008172ce0a9SAzael Avalos if (ret) 2009172ce0a9SAzael Avalos return ret; 2010172ce0a9SAzael Avalos if (state != 0 && state != 1) 2011172ce0a9SAzael Avalos return -EINVAL; 2012172ce0a9SAzael Avalos 2013172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2014172ce0a9SAzael Avalos if (ret) 2015172ce0a9SAzael Avalos return ret; 2016172ce0a9SAzael Avalos 2017172ce0a9SAzael Avalos return count; 2018172ce0a9SAzael Avalos } 2019172ce0a9SAzael Avalos 2020360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2021360f0f39SAzael Avalos struct attribute *attr, int idx) 2022360f0f39SAzael Avalos { 2023360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2024360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2025360f0f39SAzael Avalos bool exists = true; 2026360f0f39SAzael Avalos 2027360f0f39SAzael Avalos if (attr == &dev_attr_kbd_backlight_mode.attr) 2028360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2029360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2030360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 20319d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 20329d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 20335a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 20345a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2035e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2036e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2037182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2038182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2039bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2040bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2041172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2042172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2043360f0f39SAzael Avalos 2044360f0f39SAzael Avalos return exists ? attr->mode : 0; 2045360f0f39SAzael Avalos } 2046360f0f39SAzael Avalos 20471f28f290SAzael Avalos /* 20481f28f290SAzael Avalos * Hotkeys 20491f28f290SAzael Avalos */ 20501f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 20511f28f290SAzael Avalos { 20521f28f290SAzael Avalos acpi_status status; 20531f28f290SAzael Avalos u32 result; 20541f28f290SAzael Avalos 20551f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 20561f28f290SAzael Avalos "ENAB", NULL, NULL); 20571f28f290SAzael Avalos if (ACPI_FAILURE(status)) 20581f28f290SAzael Avalos return -ENODEV; 20591f28f290SAzael Avalos 20601f28f290SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 20611f28f290SAzael Avalos if (result == TOS_FAILURE) 20621f28f290SAzael Avalos return -EIO; 20631f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 20641f28f290SAzael Avalos return -ENODEV; 20651f28f290SAzael Avalos 20661f28f290SAzael Avalos return 0; 20671f28f290SAzael Avalos } 20681f28f290SAzael Avalos 206929cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 207029cd293fSSeth Forshee struct serio *port) 207129cd293fSSeth Forshee { 207298280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 207329cd293fSSeth Forshee return false; 207429cd293fSSeth Forshee 207529cd293fSSeth Forshee if (unlikely(data == 0xe0)) 207629cd293fSSeth Forshee return false; 207729cd293fSSeth Forshee 207829cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 207929cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 208029cd293fSSeth Forshee return true; 208129cd293fSSeth Forshee } 208229cd293fSSeth Forshee 208329cd293fSSeth Forshee return false; 208429cd293fSSeth Forshee } 208529cd293fSSeth Forshee 208629cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 208729cd293fSSeth Forshee { 208829cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 208929cd293fSSeth Forshee acpi_status status; 209029cd293fSSeth Forshee 209129cd293fSSeth Forshee if (!ec_handle) 209229cd293fSSeth Forshee return; 209329cd293fSSeth Forshee 209429cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 209529cd293fSSeth Forshee if (ACPI_FAILURE(status)) 209629cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 209729cd293fSSeth Forshee } 209829cd293fSSeth Forshee 209929cd293fSSeth Forshee /* 210029cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 210129cd293fSSeth Forshee */ 210229cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 210329cd293fSSeth Forshee { 210474facaf7SZhang Rui unsigned long long value; 210529cd293fSSeth Forshee acpi_status status; 210629cd293fSSeth Forshee 210774facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 210874facaf7SZhang Rui NULL, &value); 210974facaf7SZhang Rui if (ACPI_FAILURE(status)) { 211029cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 211129cd293fSSeth Forshee return -EIO; 211229cd293fSSeth Forshee } 211329cd293fSSeth Forshee 211474facaf7SZhang Rui return value; 211529cd293fSSeth Forshee } 211629cd293fSSeth Forshee 211729cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 211829cd293fSSeth Forshee int scancode) 211929cd293fSSeth Forshee { 212029cd293fSSeth Forshee if (scancode == 0x100) 212129cd293fSSeth Forshee return; 212229cd293fSSeth Forshee 212329cd293fSSeth Forshee /* act on key press; ignore key release */ 212429cd293fSSeth Forshee if (scancode & 0x80) 212529cd293fSSeth Forshee return; 212629cd293fSSeth Forshee 212729cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 212829cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 212929cd293fSSeth Forshee } 213029cd293fSSeth Forshee 213171454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 213271454d78SAzael Avalos { 213371454d78SAzael Avalos u32 hci_result, value; 213471454d78SAzael Avalos int retries = 3; 213571454d78SAzael Avalos int scancode; 213671454d78SAzael Avalos 213771454d78SAzael Avalos if (dev->info_supported) { 213871454d78SAzael Avalos scancode = toshiba_acpi_query_hotkey(dev); 213971454d78SAzael Avalos if (scancode < 0) 214071454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 214171454d78SAzael Avalos else if (scancode != 0) 214271454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 214371454d78SAzael Avalos } else if (dev->system_event_supported) { 214471454d78SAzael Avalos do { 214571454d78SAzael Avalos hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 214671454d78SAzael Avalos switch (hci_result) { 214771454d78SAzael Avalos case TOS_SUCCESS: 214871454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 214971454d78SAzael Avalos break; 215071454d78SAzael Avalos case TOS_NOT_SUPPORTED: 215171454d78SAzael Avalos /* 215271454d78SAzael Avalos * This is a workaround for an unresolved 215371454d78SAzael Avalos * issue on some machines where system events 215471454d78SAzael Avalos * sporadically become disabled. 215571454d78SAzael Avalos */ 215671454d78SAzael Avalos hci_result = 215771454d78SAzael Avalos hci_write1(dev, HCI_SYSTEM_EVENT, 1); 215871454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 215971454d78SAzael Avalos /* fall through */ 216071454d78SAzael Avalos default: 216171454d78SAzael Avalos retries--; 216271454d78SAzael Avalos break; 216371454d78SAzael Avalos } 216471454d78SAzael Avalos } while (retries && hci_result != TOS_FIFO_EMPTY); 216571454d78SAzael Avalos } 216671454d78SAzael Avalos } 216771454d78SAzael Avalos 2168b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 21696335e4d5SMatthew Garrett { 2170e2e19606SZhang Rui acpi_handle ec_handle; 2171135740deSSeth Forshee int error; 217229cd293fSSeth Forshee u32 hci_result; 2173fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2174135740deSSeth Forshee 2175135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2176b222cca6SJoe Perches if (!dev->hotkey_dev) 2177135740deSSeth Forshee return -ENOMEM; 2178135740deSSeth Forshee 2179135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 21806e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2181135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2182135740deSSeth Forshee 2183fe808bfbSTakashi Iwai if (dmi_check_system(toshiba_alt_keymap_dmi)) 2184fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2185fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2186135740deSSeth Forshee if (error) 2187135740deSSeth Forshee goto err_free_dev; 2188135740deSSeth Forshee 218929cd293fSSeth Forshee /* 219029cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 219129cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 219229cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 219329cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 219429cd293fSSeth Forshee * for this purpose. 219529cd293fSSeth Forshee */ 219629cd293fSSeth Forshee ec_handle = ec_get_handle(); 2197e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 219829cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 219929cd293fSSeth Forshee 220029cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 220129cd293fSSeth Forshee if (error) { 220229cd293fSSeth Forshee pr_err("Error installing key filter\n"); 220329cd293fSSeth Forshee goto err_free_keymap; 220429cd293fSSeth Forshee } 220529cd293fSSeth Forshee 220629cd293fSSeth Forshee dev->ntfy_supported = 1; 220729cd293fSSeth Forshee } 220829cd293fSSeth Forshee 220929cd293fSSeth Forshee /* 221029cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 221129cd293fSSeth Forshee * method when it is available. 221229cd293fSSeth Forshee */ 2213e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 221429cd293fSSeth Forshee dev->info_supported = 1; 2215e2e19606SZhang Rui else { 2216893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); 22171864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 221829cd293fSSeth Forshee dev->system_event_supported = 1; 221929cd293fSSeth Forshee } 222029cd293fSSeth Forshee 222129cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 222229cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 222329cd293fSSeth Forshee goto err_remove_filter; 222429cd293fSSeth Forshee } 222529cd293fSSeth Forshee 22261f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 22271f28f290SAzael Avalos if (error) { 2228135740deSSeth Forshee pr_info("Unable to enable hotkeys\n"); 222929cd293fSSeth Forshee goto err_remove_filter; 2230135740deSSeth Forshee } 2231135740deSSeth Forshee 2232135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2233135740deSSeth Forshee if (error) { 2234135740deSSeth Forshee pr_info("Unable to register input device\n"); 223529cd293fSSeth Forshee goto err_remove_filter; 2236135740deSSeth Forshee } 2237135740deSSeth Forshee 2238135740deSSeth Forshee return 0; 2239135740deSSeth Forshee 224029cd293fSSeth Forshee err_remove_filter: 224129cd293fSSeth Forshee if (dev->ntfy_supported) 224229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2243135740deSSeth Forshee err_free_keymap: 2244135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2245135740deSSeth Forshee err_free_dev: 2246135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2247135740deSSeth Forshee dev->hotkey_dev = NULL; 2248135740deSSeth Forshee return error; 2249135740deSSeth Forshee } 2250135740deSSeth Forshee 2251b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 225262cce752SSeth Forshee { 225362cce752SSeth Forshee struct backlight_properties props; 225462cce752SSeth Forshee int brightness; 225562cce752SSeth Forshee int ret; 2256121b7b0dSAkio Idehara bool enabled; 225762cce752SSeth Forshee 225862cce752SSeth Forshee /* 225962cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 226062cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 226162cce752SSeth Forshee * so only register the backlight device if the backlight method 226262cce752SSeth Forshee * supports both reads and writes. 226362cce752SSeth Forshee */ 226462cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 226562cce752SSeth Forshee if (brightness < 0) 226662cce752SSeth Forshee return 0; 226762cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 226862cce752SSeth Forshee if (ret) { 226962cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 227062cce752SSeth Forshee return 0; 227162cce752SSeth Forshee } 227262cce752SSeth Forshee 2273121b7b0dSAkio Idehara /* Determine whether or not BIOS supports transflective backlight */ 2274121b7b0dSAkio Idehara ret = get_tr_backlight_status(dev, &enabled); 2275121b7b0dSAkio Idehara dev->tr_backlight_supported = !ret; 2276121b7b0dSAkio Idehara 227753039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 227862cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 227962cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 228062cce752SSeth Forshee 2281121b7b0dSAkio Idehara /* adding an extra level and having 0 change to transflective mode */ 2282121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2283121b7b0dSAkio Idehara props.max_brightness++; 2284121b7b0dSAkio Idehara 228562cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 228662cce752SSeth Forshee &dev->acpi_dev->dev, 228762cce752SSeth Forshee dev, 228862cce752SSeth Forshee &toshiba_backlight_data, 228962cce752SSeth Forshee &props); 229062cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 229162cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 229262cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 229362cce752SSeth Forshee dev->backlight_dev = NULL; 229462cce752SSeth Forshee return ret; 229562cce752SSeth Forshee } 229662cce752SSeth Forshee 229762cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 229862cce752SSeth Forshee return 0; 229962cce752SSeth Forshee } 230062cce752SSeth Forshee 230151fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2302135740deSSeth Forshee { 2303135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2304135740deSSeth Forshee 230536d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2306135740deSSeth Forshee 2307360f0f39SAzael Avalos if (dev->sysfs_created) 2308360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2309360f0f39SAzael Avalos &toshiba_attr_group); 2310360f0f39SAzael Avalos 231129cd293fSSeth Forshee if (dev->ntfy_supported) { 231229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 231329cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 231429cd293fSSeth Forshee } 231529cd293fSSeth Forshee 2316135740deSSeth Forshee if (dev->hotkey_dev) { 2317135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2318135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2319135740deSSeth Forshee } 2320135740deSSeth Forshee 2321135740deSSeth Forshee if (dev->bt_rfk) { 2322135740deSSeth Forshee rfkill_unregister(dev->bt_rfk); 2323135740deSSeth Forshee rfkill_destroy(dev->bt_rfk); 2324135740deSSeth Forshee } 2325135740deSSeth Forshee 2326135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2327135740deSSeth Forshee 232836d03f93SSeth Forshee if (dev->illumination_supported) 2329135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2330135740deSSeth Forshee 2331360f0f39SAzael Avalos if (dev->kbd_led_registered) 2332360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2333360f0f39SAzael Avalos 2334def6c4e2SAzael Avalos if (dev->eco_supported) 2335def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2336def6c4e2SAzael Avalos 233729cd293fSSeth Forshee if (toshiba_acpi) 233829cd293fSSeth Forshee toshiba_acpi = NULL; 233929cd293fSSeth Forshee 2340135740deSSeth Forshee kfree(dev); 2341135740deSSeth Forshee 2342135740deSSeth Forshee return 0; 2343135740deSSeth Forshee } 2344135740deSSeth Forshee 2345b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2346a540d6b5SSeth Forshee { 2347e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2348a540d6b5SSeth Forshee return "GHCI"; 2349a540d6b5SSeth Forshee 2350e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2351a540d6b5SSeth Forshee return "SPFC"; 2352a540d6b5SSeth Forshee 2353a540d6b5SSeth Forshee return NULL; 2354a540d6b5SSeth Forshee } 2355a540d6b5SSeth Forshee 2356b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2357135740deSSeth Forshee { 2358135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2359a540d6b5SSeth Forshee const char *hci_method; 236036d03f93SSeth Forshee u32 dummy; 2361135740deSSeth Forshee bool bt_present; 2362135740deSSeth Forshee int ret = 0; 2363135740deSSeth Forshee 236429cd293fSSeth Forshee if (toshiba_acpi) 236529cd293fSSeth Forshee return -EBUSY; 236629cd293fSSeth Forshee 2367135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2368135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2369135740deSSeth Forshee 2370a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2371a540d6b5SSeth Forshee if (!hci_method) { 2372a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 23736e02cc7eSSeth Forshee return -ENODEV; 2374a540d6b5SSeth Forshee } 23756e02cc7eSSeth Forshee 2376135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2377135740deSSeth Forshee if (!dev) 2378135740deSSeth Forshee return -ENOMEM; 2379135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2380a540d6b5SSeth Forshee dev->method_hci = hci_method; 2381135740deSSeth Forshee acpi_dev->driver_data = dev; 2382360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2383135740deSSeth Forshee 23846e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2385135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2386135740deSSeth Forshee 2387135740deSSeth Forshee mutex_init(&dev->mutex); 2388135740deSSeth Forshee 238962cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 239062cce752SSeth Forshee if (ret) 2391135740deSSeth Forshee goto error; 2392135740deSSeth Forshee 2393135740deSSeth Forshee /* Register rfkill switch for Bluetooth */ 23941864bbc2SAzael Avalos if (hci_get_bt_present(dev, &bt_present) == TOS_SUCCESS && bt_present) { 2395135740deSSeth Forshee dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth", 2396135740deSSeth Forshee &acpi_dev->dev, 2397135740deSSeth Forshee RFKILL_TYPE_BLUETOOTH, 2398135740deSSeth Forshee &toshiba_rfk_ops, 2399135740deSSeth Forshee dev); 2400135740deSSeth Forshee if (!dev->bt_rfk) { 2401135740deSSeth Forshee pr_err("unable to allocate rfkill device\n"); 2402135740deSSeth Forshee ret = -ENOMEM; 2403135740deSSeth Forshee goto error; 2404135740deSSeth Forshee } 2405135740deSSeth Forshee 2406135740deSSeth Forshee ret = rfkill_register(dev->bt_rfk); 2407135740deSSeth Forshee if (ret) { 2408135740deSSeth Forshee pr_err("unable to register rfkill device\n"); 2409135740deSSeth Forshee rfkill_destroy(dev->bt_rfk); 2410135740deSSeth Forshee goto error; 2411135740deSSeth Forshee } 2412135740deSSeth Forshee } 2413135740deSSeth Forshee 2414135740deSSeth Forshee if (toshiba_illumination_available(dev)) { 2415135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2416135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2417135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2418135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2419135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 242036d03f93SSeth Forshee dev->illumination_supported = 1; 2421135740deSSeth Forshee } 2422135740deSSeth Forshee 2423def6c4e2SAzael Avalos if (toshiba_eco_mode_available(dev)) { 2424def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2425def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2426def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2427def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2428def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2429def6c4e2SAzael Avalos dev->eco_supported = 1; 2430def6c4e2SAzael Avalos } 2431def6c4e2SAzael Avalos 243293f8c16dSAzael Avalos dev->kbd_illum_supported = toshiba_kbd_illum_available(dev); 2433360f0f39SAzael Avalos /* 2434360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2435360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2436360f0f39SAzael Avalos */ 2437360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2438360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2439360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2440360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2441360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2442360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2443360f0f39SAzael Avalos dev->kbd_led_registered = 1; 2444360f0f39SAzael Avalos } 2445360f0f39SAzael Avalos 24469d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 24479d8658acSAzael Avalos dev->touchpad_supported = !ret; 24489d8658acSAzael Avalos 24495a2813e9SAzael Avalos ret = toshiba_accelerometer_supported(dev); 24505a2813e9SAzael Avalos dev->accelerometer_supported = !ret; 24515a2813e9SAzael Avalos 2452e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(dev, &dummy); 2453e26ffe51SAzael Avalos dev->usb_sleep_charge_supported = !ret; 2454e26ffe51SAzael Avalos 2455bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2456bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2457bb3fe01fSAzael Avalos 2458172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2459172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2460172ce0a9SAzael Avalos 246136d03f93SSeth Forshee /* Determine whether or not BIOS supports fan and video interfaces */ 246236d03f93SSeth Forshee 246336d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 246436d03f93SSeth Forshee dev->video_supported = !ret; 246536d03f93SSeth Forshee 246636d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 246736d03f93SSeth Forshee dev->fan_supported = !ret; 246836d03f93SSeth Forshee 2469360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2470360f0f39SAzael Avalos &toshiba_attr_group); 2471360f0f39SAzael Avalos if (ret) { 2472360f0f39SAzael Avalos dev->sysfs_created = 0; 2473360f0f39SAzael Avalos goto error; 2474360f0f39SAzael Avalos } 2475360f0f39SAzael Avalos dev->sysfs_created = !ret; 2476360f0f39SAzael Avalos 247736d03f93SSeth Forshee create_toshiba_proc_entries(dev); 247836d03f93SSeth Forshee 247929cd293fSSeth Forshee toshiba_acpi = dev; 248029cd293fSSeth Forshee 2481135740deSSeth Forshee return 0; 2482135740deSSeth Forshee 2483135740deSSeth Forshee error: 248451fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2485135740deSSeth Forshee return ret; 2486135740deSSeth Forshee } 2487135740deSSeth Forshee 2488135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2489135740deSSeth Forshee { 2490135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 249180546905SAzael Avalos int ret; 24926335e4d5SMatthew Garrett 249371454d78SAzael Avalos switch (event) { 249471454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 249571454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 249611948b93SSeth Forshee break; 249780546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 249880546905SAzael Avalos /* Update sysfs entries */ 249980546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 250080546905SAzael Avalos &toshiba_attr_group); 250180546905SAzael Avalos if (ret) 250280546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 250380546905SAzael Avalos break; 250471454d78SAzael Avalos case 0x81: /* Unknown */ 250571454d78SAzael Avalos case 0x82: /* Unknown */ 250671454d78SAzael Avalos case 0x83: /* Unknown */ 250771454d78SAzael Avalos case 0x8c: /* Unknown */ 250871454d78SAzael Avalos case 0x8e: /* Unknown */ 250971454d78SAzael Avalos case 0x8f: /* Unknown */ 251071454d78SAzael Avalos case 0x90: /* Unknown */ 251111948b93SSeth Forshee default: 251271454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 251311948b93SSeth Forshee break; 25146335e4d5SMatthew Garrett } 251529cd293fSSeth Forshee } 25166335e4d5SMatthew Garrett 25173567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 251843d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 251929cd293fSSeth Forshee { 252043d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 252129cd293fSSeth Forshee u32 result; 252229cd293fSSeth Forshee 252329cd293fSSeth Forshee if (dev->hotkey_dev) 2524893f3f62SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 252529cd293fSSeth Forshee 252629cd293fSSeth Forshee return 0; 252729cd293fSSeth Forshee } 252829cd293fSSeth Forshee 252943d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 253029cd293fSSeth Forshee { 253143d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 25321f28f290SAzael Avalos int error; 253329cd293fSSeth Forshee 2534e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 25351f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 25361f28f290SAzael Avalos if (error) 2537e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2538e7fdb762SBenjamin Tissoires } 253929cd293fSSeth Forshee 254029cd293fSSeth Forshee return 0; 254129cd293fSSeth Forshee } 25423567a4e2SRafael J. Wysocki #endif 25436335e4d5SMatthew Garrett 254443d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 254543d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 254643d2fd3bSRafael J. Wysocki 2547135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2548135740deSSeth Forshee .name = "Toshiba ACPI driver", 2549135740deSSeth Forshee .owner = THIS_MODULE, 2550135740deSSeth Forshee .ids = toshiba_device_ids, 2551135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2552135740deSSeth Forshee .ops = { 2553135740deSSeth Forshee .add = toshiba_acpi_add, 2554135740deSSeth Forshee .remove = toshiba_acpi_remove, 2555135740deSSeth Forshee .notify = toshiba_acpi_notify, 2556135740deSSeth Forshee }, 255743d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2558135740deSSeth Forshee }; 2559b4f9fe12SLen Brown 2560b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2561b4f9fe12SLen Brown { 2562135740deSSeth Forshee int ret; 2563b4f9fe12SLen Brown 2564f11f999eSSeth Forshee /* 2565f11f999eSSeth Forshee * Machines with this WMI guid aren't supported due to bugs in 2566f11f999eSSeth Forshee * their AML. This check relies on wmi initializing before 2567f11f999eSSeth Forshee * toshiba_acpi to guarantee guids have been identified. 2568f11f999eSSeth Forshee */ 2569f11f999eSSeth Forshee if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2570f11f999eSSeth Forshee return -ENODEV; 2571f11f999eSSeth Forshee 2572b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2573b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2574135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2575b4f9fe12SLen Brown return -ENODEV; 2576b4f9fe12SLen Brown } 2577b4f9fe12SLen Brown 2578135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2579b4f9fe12SLen Brown if (ret) { 2580135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2581135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2582135740deSSeth Forshee } 2583135740deSSeth Forshee 2584b4f9fe12SLen Brown return ret; 2585b4f9fe12SLen Brown } 2586b4f9fe12SLen Brown 2587135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 2588135740deSSeth Forshee { 2589135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 2590135740deSSeth Forshee if (toshiba_proc_dir) 2591135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2592b4f9fe12SLen Brown } 2593b4f9fe12SLen Brown 2594b4f9fe12SLen Brown module_init(toshiba_acpi_init); 2595b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 2596