Commit 3af6e98f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v4.3-1' of...

Merge tag 'platform-drivers-x86-v4.3-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86

Pull x86 platform driver updates from Darren Hart:
 "Significant work on toshiba_acpi, including new hardware support,
  refactoring, and cleanups.  Extend device support for asus, ideapad,
  and acer systems.  New surface pro 3 buttons driver.  Misc minor
  cleanups for thinkpad and hp-wireless.

  acer-wmi:
   - No rfkill on HP Omen 15 wifi

  thinkpad_acpi:
   - Remove side effects from vdbg_printk -> no_printk macro

  surface pro 3:
   - Add support driver for Surface Pro 3 buttons

  hp-wireless:
   - remove unneeded goto/label in hpwl_init

  ideapad-laptop:
   - add alternative representation for Yoga 2 to DMI table
   - Add Lenovo Yoga 3 14 to no_hw_rfkill dmi list

  asus-laptop:
   - Add key found on Asus F3M

  MAINTAINERS:
   - Remove Toshiba Linux mailing list address

  toshiba_acpi:
   - Bump driver version to 0.23
   - Remove unnecessary checks and returns in HCI/SCI functions
   - Refactor *{get, set} functions return value
   - Remove "*not supported" feature prints
   - Change *available functions return type
   - Add set_fan_status function
   - Change some variables to avoid warnings from ninja-check
   - Reorder toshiba_acpi_alt_keymap entries
   - Remove unused wireless defines
   - Transflective backlight updates
   - Avoid registering input device on WMI event laptops
   - Add /dev/toshiba_acpi device
   - Adapt /proc/acpi/toshiba/keys to TOS1900 devices"

* tag 'platform-drivers-x86-v4.3-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (21 commits)
  acer-wmi: No rfkill on HP Omen 15 wifi
  thinkpad_acpi: Remove side effects from vdbg_printk -> no_printk macro
  surface pro 3: Add support driver for Surface Pro 3 buttons
  hp-wireless: remove unneeded goto/label in hpwl_init
  ideapad-laptop: add alternative representation for Yoga 2 to DMI table
  asus-laptop: Add key found on Asus F3M
  MAINTAINERS: Remove Toshiba Linux mailing list address
  ideapad-laptop: Add Lenovo Yoga 3 14 to no_hw_rfkill dmi list
  toshiba_acpi: Bump driver version to 0.23
  toshiba_acpi: Remove unnecessary checks and returns in HCI/SCI functions
  toshiba_acpi: Refactor *{get, set} functions return value
  toshiba_acpi: Remove "*not supported" feature prints
  toshiba_acpi: Change *available functions return type
  toshiba_acpi: Add set_fan_status function
  toshiba_acpi: Change some variables to avoid warnings from ninja-check
  toshiba_acpi: Reorder toshiba_acpi_alt_keymap entries
  toshiba_acpi: Remove unused wireless defines
  toshiba_acpi: Transflective backlight updates
  toshiba_acpi: Avoid registering input device on WMI event laptops
  toshiba_acpi: Add /dev/toshiba_acpi device
  ...
parents acceba59 628b3198
...@@ -265,7 +265,7 @@ Code Seq#(hex) Include File Comments ...@@ -265,7 +265,7 @@ Code Seq#(hex) Include File Comments
's' all linux/cdk.h 's' all linux/cdk.h
't' 00-7F linux/ppp-ioctl.h 't' 00-7F linux/ppp-ioctl.h
't' 80-8F linux/isdn_ppp.h 't' 80-8F linux/isdn_ppp.h
't' 90 linux/toshiba.h 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM
'u' 00-1F linux/smb_fs.h gone 'u' 00-1F linux/smb_fs.h gone
'u' 20-3F linux/uvcvideo.h USB video class host driver 'u' 20-3F linux/uvcvideo.h USB video class host driver
'v' 00-1F linux/ext2_fs.h conflict! 'v' 00-1F linux/ext2_fs.h conflict!
......
...@@ -6847,6 +6847,12 @@ T: git git://git.monstr.eu/linux-2.6-microblaze.git ...@@ -6847,6 +6847,12 @@ T: git git://git.monstr.eu/linux-2.6-microblaze.git
S: Supported S: Supported
F: arch/microblaze/ F: arch/microblaze/
MICROSOFT SURFACE PRO 3 BUTTON DRIVER
M: Chen Yu <yu.c.chen@intel.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/surfacepro3_button.c
MICROTEK X6 SCANNER MICROTEK X6 SCANNER
M: Oliver Neukum <oliver@neukum.org> M: Oliver Neukum <oliver@neukum.org>
S: Maintained S: Maintained
...@@ -10489,7 +10495,6 @@ F: drivers/platform/x86/toshiba_haps.c ...@@ -10489,7 +10495,6 @@ F: drivers/platform/x86/toshiba_haps.c
TOSHIBA SMM DRIVER TOSHIBA SMM DRIVER
M: Jonathan Buzzard <jonathan@buzzard.org.uk> M: Jonathan Buzzard <jonathan@buzzard.org.uk>
L: tlinux-users@tce.toshiba-dme.co.jp
W: http://www.buzzard.org.uk/toshiba/ W: http://www.buzzard.org.uk/toshiba/
S: Maintained S: Maintained
F: drivers/char/toshiba.c F: drivers/char/toshiba.c
......
...@@ -919,4 +919,9 @@ config INTEL_PMC_IPC ...@@ -919,4 +919,9 @@ config INTEL_PMC_IPC
The PMC is an ARC processor which defines IPC commands for communication The PMC is an ARC processor which defines IPC commands for communication
with other entities in the CPU. with other entities in the CPU.
config SURFACE_PRO3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3 tablet"
depends on ACPI && INPUT
---help---
This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3 tablet.
endif # X86_PLATFORM_DEVICES endif # X86_PLATFORM_DEVICES
...@@ -60,3 +60,4 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o ...@@ -60,3 +60,4 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o
obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
...@@ -807,6 +807,7 @@ static const struct acpi_device_id norfkill_ids[] __initconst = { ...@@ -807,6 +807,7 @@ static const struct acpi_device_id norfkill_ids[] __initconst = {
{ "IBM0068", 0}, { "IBM0068", 0},
{ "LEN0068", 0}, { "LEN0068", 0},
{ "SNY5001", 0}, /* sony-laptop in charge */ { "SNY5001", 0}, /* sony-laptop in charge */
{ "HPQ6601", 0},
{ "", 0}, { "", 0},
}; };
......
...@@ -332,6 +332,7 @@ static const struct key_entry asus_keymap[] = { ...@@ -332,6 +332,7 @@ static const struct key_entry asus_keymap[] = {
{KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */ {KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */
{KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */ {KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */
{KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */ {KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
{KE_KEY, 0x6A, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad Fn + F9 */
{KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad */ {KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad */
{KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */ {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
{KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */ {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
......
...@@ -114,14 +114,9 @@ static int __init hpwl_init(void) ...@@ -114,14 +114,9 @@ static int __init hpwl_init(void)
pr_info("Initializing HPQ6001 module\n"); pr_info("Initializing HPQ6001 module\n");
err = acpi_bus_register_driver(&hpwl_driver); err = acpi_bus_register_driver(&hpwl_driver);
if (err) { if (err)
pr_err("Unable to register HP wireless control driver.\n"); pr_err("Unable to register HP wireless control driver.\n");
goto error_acpi_register;
}
return 0;
error_acpi_register:
return err; return err;
} }
......
...@@ -852,6 +852,20 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { ...@@ -852,6 +852,20 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"), DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
}, },
}, },
{
.ident = "Lenovo Yoga 3 14",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3 14"),
},
},
{
.ident = "Lenovo Yoga 2 11 / 13 / Pro",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
},
},
{ {
.ident = "Lenovo Yoga 3 Pro 1370", .ident = "Lenovo Yoga 3 Pro 1370",
.matches = { .matches = {
......
/*
* power/home/volume button support for
* Microsoft Surface Pro 3 tablet.
*
* Copyright (c) 2015 Intel Corporation.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/acpi.h>
#include <acpi/button.h>
#define SURFACE_BUTTON_HID "MSHW0028"
#define SURFACE_BUTTON_OBJ_NAME "VGBI"
#define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3 Buttons"
#define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
#define SURFACE_BUTTON_NOTIFY_RELEASE_POWER 0xc7
#define SURFACE_BUTTON_NOTIFY_PRESS_HOME 0xc4
#define SURFACE_BUTTON_NOTIFY_RELEASE_HOME 0xc5
#define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP 0xc0
#define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP 0xc1
#define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN 0xc2
#define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN 0xc3
ACPI_MODULE_NAME("surface pro 3 button");
MODULE_AUTHOR("Chen Yu");
MODULE_DESCRIPTION("Surface Pro3 Button Driver");
MODULE_LICENSE("GPL v2");
/*
* Power button, Home button, Volume buttons support is supposed to
* be covered by drivers/input/misc/soc_button_array.c, which is implemented
* according to "Windows ACPI Design Guide for SoC Platforms".
* However surface pro3 seems not to obey the specs, instead it uses
* device VGBI(MSHW0028) for dispatching the events.
* We choose acpi_driver rather than platform_driver/i2c_driver because
* although VGBI has an i2c resource connected to i2c controller, it
* is not embedded in any i2c controller's scope, thus neither platform_device
* will be created, nor i2c_client will be enumerated, we have to use
* acpi_driver.
*/
static const struct acpi_device_id surface_button_device_ids[] = {
{SURFACE_BUTTON_HID, 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, surface_button_device_ids);
struct surface_button {
unsigned int type;
struct input_dev *input;
char phys[32]; /* for input device */
unsigned long pushed;
bool suspended;
};
static void surface_button_notify(struct acpi_device *device, u32 event)
{
struct surface_button *button = acpi_driver_data(device);
struct input_dev *input;
int key_code = KEY_RESERVED;
bool pressed = false;
switch (event) {
/* Power button press,release handle */
case SURFACE_BUTTON_NOTIFY_PRESS_POWER:
pressed = true;
/*fall through*/
case SURFACE_BUTTON_NOTIFY_RELEASE_POWER:
key_code = KEY_POWER;
break;
/* Home button press,release handle */
case SURFACE_BUTTON_NOTIFY_PRESS_HOME:
pressed = true;
/*fall through*/
case SURFACE_BUTTON_NOTIFY_RELEASE_HOME:
key_code = KEY_LEFTMETA;
break;
/* Volume up button press,release handle */
case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP:
pressed = true;
/*fall through*/
case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP:
key_code = KEY_VOLUMEUP;
break;
/* Volume down button press,release handle */
case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN:
pressed = true;
/*fall through*/
case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN:
key_code = KEY_VOLUMEDOWN;
break;
default:
dev_info_ratelimited(&device->dev,
"Unsupported event [0x%x]\n", event);
break;
}
input = button->input;
if (KEY_RESERVED == key_code)
return;
if (pressed)
pm_wakeup_event(&device->dev, 0);
if (button->suspended)
return;
input_report_key(input, key_code, pressed?1:0);
input_sync(input);
}
#ifdef CONFIG_PM_SLEEP
static int surface_button_suspend(struct device *dev)
{
struct acpi_device *device = to_acpi_device(dev);
struct surface_button *button = acpi_driver_data(device);
button->suspended = true;
return 0;
}
static int surface_button_resume(struct device *dev)
{
struct acpi_device *device = to_acpi_device(dev);
struct surface_button *button = acpi_driver_data(device);
button->suspended = false;
return 0;
}
#endif
static int surface_button_add(struct acpi_device *device)
{
struct surface_button *button;
struct input_dev *input;
const char *hid = acpi_device_hid(device);
char *name;
int error;
if (strncmp(acpi_device_bid(device), SURFACE_BUTTON_OBJ_NAME,
strlen(SURFACE_BUTTON_OBJ_NAME)))
return -ENODEV;
button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
if (!button)
return -ENOMEM;
device->driver_data = button;
button->input = input = input_allocate_device();
if (!input) {
error = -ENOMEM;
goto err_free_button;
}
name = acpi_device_name(device);
strcpy(name, SURFACE_BUTTON_DEVICE_NAME);
snprintf(button->phys, sizeof(button->phys), "%s/buttons", hid);
input->name = name;
input->phys = button->phys;
input->id.bustype = BUS_HOST;
input->dev.parent = &device->dev;
input_set_capability(input, EV_KEY, KEY_POWER);
input_set_capability(input, EV_KEY, KEY_LEFTMETA);
input_set_capability(input, EV_KEY, KEY_VOLUMEUP);
input_set_capability(input, EV_KEY, KEY_VOLUMEDOWN);
error = input_register_device(input);
if (error)
goto err_free_input;
dev_info(&device->dev,
"%s [%s]\n", name, acpi_device_bid(device));
return 0;
err_free_input:
input_free_device(input);
err_free_button:
kfree(button);
return error;
}
static int surface_button_remove(struct acpi_device *device)
{
struct surface_button *button = acpi_driver_data(device);
input_unregister_device(button->input);
kfree(button);
return 0;
}
static SIMPLE_DEV_PM_OPS(surface_button_pm,
surface_button_suspend, surface_button_resume);
static struct acpi_driver surface_button_driver = {
.name = "surface_pro3_button",
.class = "SurfacePro3",
.ids = surface_button_device_ids,
.ops = {
.add = surface_button_add,
.remove = surface_button_remove,
.notify = surface_button_notify,
},
.drv.pm = &surface_button_pm,
};
module_acpi_driver(surface_button_driver);
...@@ -402,7 +402,7 @@ static const char *str_supported(int is_supported); ...@@ -402,7 +402,7 @@ static const char *str_supported(int is_supported);
#else #else
static inline const char *str_supported(int is_supported) { return ""; } static inline const char *str_supported(int is_supported) { return ""; }
#define vdbg_printk(a_dbg_level, format, arg...) \ #define vdbg_printk(a_dbg_level, format, arg...) \
no_printk(format, ##arg) do { if (0) no_printk(format, ##arg); } while (0)
#endif #endif
static void tpacpi_log_usertask(const char * const what) static void tpacpi_log_usertask(const char * const what)
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define TOSHIBA_ACPI_VERSION "0.22" #define TOSHIBA_ACPI_VERSION "0.23"
#define PROC_INTERFACE_VERSION 1 #define PROC_INTERFACE_VERSION 1
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/toshiba.h>
#include <acpi/video.h> #include <acpi/video.h>
MODULE_AUTHOR("John Belmonte"); MODULE_AUTHOR("John Belmonte");
...@@ -91,6 +93,7 @@ MODULE_LICENSE("GPL"); ...@@ -91,6 +93,7 @@ MODULE_LICENSE("GPL");
/* Return codes */ /* Return codes */
#define TOS_SUCCESS 0x0000 #define TOS_SUCCESS 0x0000
#define TOS_SUCCESS2 0x0001
#define TOS_OPEN_CLOSE_OK 0x0044 #define TOS_OPEN_CLOSE_OK 0x0044
#define TOS_FAILURE 0x1000 #define TOS_FAILURE 0x1000
#define TOS_NOT_SUPPORTED 0x8000 #define TOS_NOT_SUPPORTED 0x8000
...@@ -111,7 +114,6 @@ MODULE_LICENSE("GPL"); ...@@ -111,7 +114,6 @@ MODULE_LICENSE("GPL");
#define HCI_VIDEO_OUT 0x001c #define HCI_VIDEO_OUT 0x001c
#define HCI_HOTKEY_EVENT 0x001e #define HCI_HOTKEY_EVENT 0x001e
#define HCI_LCD_BRIGHTNESS 0x002a #define HCI_LCD_BRIGHTNESS 0x002a
#define HCI_WIRELESS 0x0056
#define HCI_ACCELEROMETER 0x006d #define HCI_ACCELEROMETER 0x006d
#define HCI_KBD_ILLUMINATION 0x0095 #define HCI_KBD_ILLUMINATION 0x0095
#define HCI_ECO_MODE 0x0097 #define HCI_ECO_MODE 0x0097
...@@ -140,10 +142,6 @@ MODULE_LICENSE("GPL"); ...@@ -140,10 +142,6 @@ MODULE_LICENSE("GPL");
#define HCI_VIDEO_OUT_LCD 0x1 #define HCI_VIDEO_OUT_LCD 0x1
#define HCI_VIDEO_OUT_CRT 0x2 #define HCI_VIDEO_OUT_CRT 0x2
#define HCI_VIDEO_OUT_TV 0x4 #define HCI_VIDEO_OUT_TV 0x4
#define HCI_WIRELESS_KILL_SWITCH 0x01
#define HCI_WIRELESS_BT_PRESENT 0x0f
#define HCI_WIRELESS_BT_ATTACH 0x40
#define HCI_WIRELESS_BT_POWER 0x80
#define SCI_KBD_MODE_MASK 0x1f #define SCI_KBD_MODE_MASK 0x1f
#define SCI_KBD_MODE_FNZ 0x1 #define SCI_KBD_MODE_FNZ 0x1
#define SCI_KBD_MODE_AUTO 0x2 #define SCI_KBD_MODE_AUTO 0x2
...@@ -170,6 +168,7 @@ struct toshiba_acpi_dev { ...@@ -170,6 +168,7 @@ struct toshiba_acpi_dev {
struct led_classdev led_dev; struct led_classdev led_dev;
struct led_classdev kbd_led; struct led_classdev kbd_led;
struct led_classdev eco_led; struct led_classdev eco_led;
struct miscdevice miscdev;
int force_fan; int force_fan;
int last_key_event; int last_key_event;
...@@ -189,7 +188,6 @@ struct toshiba_acpi_dev { ...@@ -189,7 +188,6 @@ struct toshiba_acpi_dev {
unsigned int info_supported:1; unsigned int info_supported:1;
unsigned int tr_backlight_supported:1; unsigned int tr_backlight_supported:1;
unsigned int kbd_illum_supported:1; unsigned int kbd_illum_supported:1;
unsigned int kbd_led_registered:1;
unsigned int touchpad_supported:1; unsigned int touchpad_supported:1;
unsigned int eco_supported:1; unsigned int eco_supported:1;
unsigned int accelerometer_supported:1; unsigned int accelerometer_supported:1;
...@@ -200,6 +198,10 @@ struct toshiba_acpi_dev { ...@@ -200,6 +198,10 @@ struct toshiba_acpi_dev {
unsigned int panel_power_on_supported:1; unsigned int panel_power_on_supported:1;
unsigned int usb_three_supported:1; unsigned int usb_three_supported:1;
unsigned int sysfs_created:1; unsigned int sysfs_created:1;
bool kbd_led_registered;
bool illumination_led_registered;
bool eco_led_registered;
}; };
static struct toshiba_acpi_dev *toshiba_acpi; static struct toshiba_acpi_dev *toshiba_acpi;
...@@ -248,16 +250,16 @@ static const struct key_entry toshiba_acpi_keymap[] = { ...@@ -248,16 +250,16 @@ static const struct key_entry toshiba_acpi_keymap[] = {
}; };
static const struct key_entry toshiba_acpi_alt_keymap[] = { static const struct key_entry toshiba_acpi_alt_keymap[] = {
{ KE_KEY, 0x157, { KEY_MUTE } },
{ KE_KEY, 0x102, { KEY_ZOOMOUT } }, { KE_KEY, 0x102, { KEY_ZOOMOUT } },
{ KE_KEY, 0x103, { KEY_ZOOMIN } }, { KE_KEY, 0x103, { KEY_ZOOMIN } },
{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
{ KE_KEY, 0x139, { KEY_ZOOMRESET } }, { KE_KEY, 0x139, { KEY_ZOOMRESET } },
{ KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
{ KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0x158, { KEY_WLAN } }, { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
{ KE_KEY, 0x157, { KEY_MUTE } },
{ KE_KEY, 0x158, { KEY_WLAN } },
{ KE_END, 0 }, { KE_END, 0 },
}; };
...@@ -441,26 +443,24 @@ static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) ...@@ -441,26 +443,24 @@ static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
} }
/* Illumination support */ /* Illumination support */
static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) static void toshiba_illumination_available(struct toshiba_acpi_dev *dev)
{ {
u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
acpi_status status; acpi_status status;
dev->illumination_supported = 0;
dev->illumination_led_registered = false;
if (!sci_open(dev)) if (!sci_open(dev))
return 0; return;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
sci_close(dev); sci_close(dev);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status))
pr_err("ACPI call to query Illumination support failed\n"); pr_err("ACPI call to query Illumination support failed\n");
return 0; else if (out[0] == TOS_SUCCESS)
} else if (out[0] == TOS_NOT_SUPPORTED) { dev->illumination_supported = 1;
pr_info("Illumination device not available\n");
return 0;
}
return 1;
} }
static void toshiba_illumination_set(struct led_classdev *cdev, static void toshiba_illumination_set(struct led_classdev *cdev,
...@@ -468,7 +468,8 @@ static void toshiba_illumination_set(struct led_classdev *cdev, ...@@ -468,7 +468,8 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
{ {
struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev *dev = container_of(cdev,
struct toshiba_acpi_dev, led_dev); struct toshiba_acpi_dev, led_dev);
u32 state, result; u32 result;
u32 state;
/* First request : initialize communication. */ /* First request : initialize communication. */
if (!sci_open(dev)) if (!sci_open(dev))
...@@ -478,13 +479,8 @@ static void toshiba_illumination_set(struct led_classdev *cdev, ...@@ -478,13 +479,8 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
state = brightness ? 1 : 0; state = brightness ? 1 : 0;
result = sci_write(dev, SCI_ILLUMINATION, state); result = sci_write(dev, SCI_ILLUMINATION, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call for illumination failed\n"); pr_err("ACPI call for illumination failed\n");
return;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Illumination not supported\n");
return;
}
} }
static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
...@@ -500,11 +496,10 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) ...@@ -500,11 +496,10 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
/* Check the illumination */ /* Check the illumination */
result = sci_read(dev, SCI_ILLUMINATION, &state); result = sci_read(dev, SCI_ILLUMINATION, &state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { if (result == TOS_FAILURE) {
pr_err("ACPI call for illumination failed\n"); pr_err("ACPI call for illumination failed\n");
return LED_OFF; return LED_OFF;
} else if (result == TOS_NOT_SUPPORTED) { } else if (result != TOS_SUCCESS) {
pr_info("Illumination not supported\n");
return LED_OFF; return LED_OFF;
} }
...@@ -512,41 +507,40 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) ...@@ -512,41 +507,40 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
} }
/* KBD Illumination */ /* KBD Illumination */
static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
{ {
u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
acpi_status status; acpi_status status;
dev->kbd_illum_supported = 0;
dev->kbd_led_registered = false;
if (!sci_open(dev)) if (!sci_open(dev))
return 0; return;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
sci_close(dev); sci_close(dev);
if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { if (ACPI_FAILURE(status)) {
pr_err("ACPI call to query kbd illumination support failed\n"); pr_err("ACPI call to query kbd illumination support failed\n");
return 0; } else if (out[0] == TOS_SUCCESS) {
} else if (out[0] == TOS_NOT_SUPPORTED) { /*
pr_info("Keyboard illumination not available\n"); * Check for keyboard backlight timeout max value,
return 0; * previous kbd backlight implementation set this to
* 0x3c0003, and now the new implementation set this
* to 0x3c001a, use this to distinguish between them.
*/
if (out[3] == SCI_KBD_TIME_MAX)
dev->kbd_type = 2;
else
dev->kbd_type = 1;
/* Get the current keyboard backlight mode */
dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
/* Get the current time (1-60 seconds) */
dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
/* Flag as supported */
dev->kbd_illum_supported = 1;
} }
/*
* Check for keyboard backlight timeout max value,
* previous kbd backlight implementation set this to
* 0x3c0003, and now the new implementation set this
* to 0x3c001a, use this to distinguish between them.
*/
if (out[3] == SCI_KBD_TIME_MAX)
dev->kbd_type = 2;
else
dev->kbd_type = 1;
/* Get the current keyboard backlight mode */
dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
/* Get the current time (1-60 seconds) */
dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
return 1;
} }
static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
...@@ -558,15 +552,12 @@ static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) ...@@ -558,15 +552,12 @@ static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { if (result == TOS_FAILURE)
pr_err("ACPI call to set KBD backlight status failed\n"); pr_err("ACPI call to set KBD backlight status failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Keyboard backlight status not supported\n");
return -ENODEV; return -ENODEV;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
...@@ -578,30 +569,27 @@ static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) ...@@ -578,30 +569,27 @@ static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { if (result == TOS_FAILURE)
pr_err("ACPI call to get KBD backlight status failed\n"); pr_err("ACPI call to get KBD backlight status failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Keyboard backlight status not supported\n");
return -ENODEV; return -ENODEV;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
{ {
struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev *dev = container_of(cdev,
struct toshiba_acpi_dev, kbd_led); struct toshiba_acpi_dev, kbd_led);
u32 state, result; u32 result;
u32 state;
/* Check the keyboard backlight state */ /* Check the keyboard backlight state */
result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); result = hci_read(dev, HCI_KBD_ILLUMINATION, &state);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { if (result == TOS_FAILURE) {
pr_err("ACPI call to get the keyboard backlight failed\n"); pr_err("ACPI call to get the keyboard backlight failed\n");
return LED_OFF; return LED_OFF;
} else if (result == TOS_NOT_SUPPORTED) { } else if (result != TOS_SUCCESS) {
pr_info("Keyboard backlight not supported\n");
return LED_OFF; return LED_OFF;
} }
...@@ -613,18 +601,14 @@ static void toshiba_kbd_backlight_set(struct led_classdev *cdev, ...@@ -613,18 +601,14 @@ static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
{ {
struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev *dev = container_of(cdev,
struct toshiba_acpi_dev, kbd_led); struct toshiba_acpi_dev, kbd_led);
u32 state, result; u32 result;
u32 state;
/* Set the keyboard backlight state */ /* Set the keyboard backlight state */
state = brightness ? 1 : 0; state = brightness ? 1 : 0;
result = hci_write(dev, HCI_KBD_ILLUMINATION, state); result = hci_write(dev, HCI_KBD_ILLUMINATION, state);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { if (result == TOS_FAILURE)
pr_err("ACPI call to set KBD Illumination mode failed\n"); pr_err("ACPI call to set KBD Illumination mode failed\n");
return;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Keyboard backlight not supported\n");
return;
}
} }
/* TouchPad support */ /* TouchPad support */
...@@ -637,14 +621,12 @@ static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) ...@@ -637,14 +621,12 @@ static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
result = sci_write(dev, SCI_TOUCHPAD, state); result = sci_write(dev, SCI_TOUCHPAD, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to set the touchpad failed\n"); pr_err("ACPI call to set the touchpad failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
return -ENODEV; return -ENODEV;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
...@@ -656,28 +638,27 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) ...@@ -656,28 +638,27 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
result = sci_read(dev, SCI_TOUCHPAD, state); result = sci_read(dev, SCI_TOUCHPAD, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to query the touchpad failed\n"); pr_err("ACPI call to query the touchpad failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
return -ENODEV; return -ENODEV;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
/* Eco Mode support */ /* Eco Mode support */
static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
{ {
acpi_status status; acpi_status status;
u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
dev->eco_supported = 0;
dev->eco_led_registered = false;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
pr_err("ACPI call to get ECO led failed\n"); pr_err("ACPI call to get ECO led failed\n");
} else if (out[0] == TOS_NOT_INSTALLED) {
pr_info("ECO led not installed");
} else if (out[0] == TOS_INPUT_DATA_ERROR) { } else if (out[0] == TOS_INPUT_DATA_ERROR) {
/* /*
* If we receive 0x8300 (Input Data Error), it means that the * If we receive 0x8300 (Input Data Error), it means that the
...@@ -690,13 +671,11 @@ static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) ...@@ -690,13 +671,11 @@ static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
*/ */
in[3] = 1; in[3] = 1;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) if (ACPI_FAILURE(status))
pr_err("ACPI call to get ECO led failed\n"); pr_err("ACPI call to get ECO led failed\n");
else if (out[0] == TOS_SUCCESS) else if (out[0] == TOS_SUCCESS)
return 1; dev->eco_supported = 1;
} }
return 0;
} }
static enum led_brightness static enum led_brightness
...@@ -709,9 +688,11 @@ toshiba_eco_mode_get_status(struct led_classdev *cdev) ...@@ -709,9 +688,11 @@ toshiba_eco_mode_get_status(struct led_classdev *cdev)
acpi_status status; acpi_status status;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { if (ACPI_FAILURE(status)) {
pr_err("ACPI call to get ECO led failed\n"); pr_err("ACPI call to get ECO led failed\n");
return LED_OFF; return LED_OFF;
} else if (out[0] != TOS_SUCCESS) {
return LED_OFF;
} }
return out[2] ? LED_FULL : LED_OFF; return out[2] ? LED_FULL : LED_OFF;
...@@ -729,41 +710,32 @@ static void toshiba_eco_mode_set_status(struct led_classdev *cdev, ...@@ -729,41 +710,32 @@ static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
/* Switch the Eco Mode led on/off */ /* Switch the Eco Mode led on/off */
in[2] = (brightness) ? 1 : 0; in[2] = (brightness) ? 1 : 0;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { if (ACPI_FAILURE(status))
pr_err("ACPI call to set ECO led failed\n"); pr_err("ACPI call to set ECO led failed\n");
return;
}
} }
/* Accelerometer support */ /* Accelerometer support */
static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev)
{ {
u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
acpi_status status; acpi_status status;
dev->accelerometer_supported = 0;
/* /*
* Check if the accelerometer call exists, * Check if the accelerometer call exists,
* this call also serves as initialization * this call also serves as initialization
*/ */
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { if (ACPI_FAILURE(status))
pr_err("ACPI call to query the accelerometer failed\n"); pr_err("ACPI call to query the accelerometer failed\n");
return -EIO; else if (out[0] == TOS_SUCCESS)
} else if (out[0] == TOS_DATA_NOT_AVAILABLE || dev->accelerometer_supported = 1;
out[0] == TOS_NOT_INITIALIZED) {
pr_err("Accelerometer not initialized\n");
return -EIO;
} else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("Accelerometer not supported\n");
return -ENODEV;
}
return 0;
} }
static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
u32 *xy, u32 *z) u32 *xy, u32 *z)
{ {
u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
...@@ -771,15 +743,18 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, ...@@ -771,15 +743,18 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
/* Check the Accelerometer status */ /* Check the Accelerometer status */
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { if (ACPI_FAILURE(status)) {
pr_err("ACPI call to query the accelerometer failed\n"); pr_err("ACPI call to query the accelerometer failed\n");
return -EIO; return -EIO;
} else if (out[0] == TOS_NOT_SUPPORTED) {
return -ENODEV;
} else if (out[0] == TOS_SUCCESS) {
*xy = out[2];
*z = out[4];
return 0;
} }
*xy = out[2]; return -EIO;
*z = out[4];
return 0;
} }
/* Sleep (Charge and Music) utilities support */ /* Sleep (Charge and Music) utilities support */
...@@ -789,7 +764,6 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) ...@@ -789,7 +764,6 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev)
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
acpi_status status; acpi_status status;
/* Set the feature to "not supported" in case of error */
dev->usb_sleep_charge_supported = 0; dev->usb_sleep_charge_supported = 0;
if (!sci_open(dev)) if (!sci_open(dev))
...@@ -801,7 +775,6 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) ...@@ -801,7 +775,6 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev)
sci_close(dev); sci_close(dev);
return; return;
} else if (out[0] == TOS_NOT_SUPPORTED) { } else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
sci_close(dev); sci_close(dev);
return; return;
} else if (out[0] == TOS_SUCCESS) { } else if (out[0] == TOS_SUCCESS) {
...@@ -810,25 +783,15 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) ...@@ -810,25 +783,15 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev)
in[5] = SCI_USB_CHARGE_BAT_LVL; in[5] = SCI_USB_CHARGE_BAT_LVL;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
sci_close(dev);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
sci_close(dev);
return;
} else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
sci_close(dev);
return;
} else if (out[0] == TOS_SUCCESS) { } else if (out[0] == TOS_SUCCESS) {
dev->usbsc_bat_level = out[2]; dev->usbsc_bat_level = out[2];
/* /* Flag as supported */
* If we reach this point, it means that the laptop has support
* for this feature and all values are initialized.
* Set it as supported.
*/
dev->usb_sleep_charge_supported = 1; dev->usb_sleep_charge_supported = 1;
} }
sci_close(dev);
} }
static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
...@@ -841,17 +804,12 @@ static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, ...@@ -841,17 +804,12 @@ static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to set USB S&C mode failed\n"); pr_err("ACPI call to set USB S&C mode failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV; return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
...@@ -864,17 +822,12 @@ static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, ...@@ -864,17 +822,12 @@ static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to set USB S&C mode failed\n"); pr_err("ACPI call to set USB S&C mode failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV; return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
...@@ -892,17 +845,14 @@ static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, ...@@ -892,17 +845,14 @@ static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
sci_close(dev); sci_close(dev);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
pr_err("ACPI call to get USB S&C battery level failed\n"); pr_err("ACPI call to get USB S&C battery level failed\n");
return -EIO;
} else if (out[0] == TOS_NOT_SUPPORTED) { } else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV; return -ENODEV;
} else if (out[0] == TOS_INPUT_DATA_ERROR) { } else if (out[0] == TOS_SUCCESS) {
return -EIO; *mode = out[2];
return 0;
} }
*mode = out[2]; return -EIO;
return 0;
} }
static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
...@@ -919,17 +869,12 @@ static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, ...@@ -919,17 +869,12 @@ static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
in[5] = SCI_USB_CHARGE_BAT_LVL; in[5] = SCI_USB_CHARGE_BAT_LVL;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
sci_close(dev); sci_close(dev);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status))
pr_err("ACPI call to set USB S&C battery level failed\n"); pr_err("ACPI call to set USB S&C battery level failed\n");
return -EIO; else if (out[0] == TOS_NOT_SUPPORTED)
} else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV; return -ENODEV;
} else if (out[0] == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return out[0] == TOS_SUCCESS ? 0 : -EIO;
} }
static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
...@@ -947,16 +892,14 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, ...@@ -947,16 +892,14 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
sci_close(dev); sci_close(dev);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
pr_err("ACPI call to get USB Rapid Charge failed\n"); pr_err("ACPI call to get USB Rapid Charge failed\n");
return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) {
} else if (out[0] == TOS_NOT_SUPPORTED ||
out[0] == TOS_INPUT_DATA_ERROR) {
pr_info("USB Rapid Charge not supported\n");
return -ENODEV; return -ENODEV;
} else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) {
*state = out[2];
return 0;
} }
*state = out[2]; return -EIO;
return 0;
} }
static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
...@@ -973,17 +916,12 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, ...@@ -973,17 +916,12 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
in[5] = SCI_USB_CHARGE_RAPID_DSP; in[5] = SCI_USB_CHARGE_RAPID_DSP;
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
sci_close(dev); sci_close(dev);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status))
pr_err("ACPI call to set USB Rapid Charge failed\n"); pr_err("ACPI call to set USB Rapid Charge failed\n");
return -EIO; else if (out[0] == TOS_NOT_SUPPORTED)
} else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("USB Rapid Charge not supported\n");
return -ENODEV; return -ENODEV;
} else if (out[0] == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO;
} }
static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
...@@ -995,17 +933,12 @@ static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) ...@@ -995,17 +933,12 @@ static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to get Sleep and Music failed\n"); pr_err("ACPI call to get Sleep and Music failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Sleep and Music not supported\n");
return -ENODEV; return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return result = TOS_SUCCESS ? 0 : -EIO;
} }
static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
...@@ -1017,17 +950,12 @@ static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) ...@@ -1017,17 +950,12 @@ static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to set Sleep and Music failed\n"); pr_err("ACPI call to set Sleep and Music failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Sleep and Music not supported\n");
return -ENODEV; return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
/* Keyboard function keys */ /* Keyboard function keys */
...@@ -1040,15 +968,12 @@ static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) ...@@ -1040,15 +968,12 @@ static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode)
result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { if (result == TOS_FAILURE)
pr_err("ACPI call to get KBD function keys failed\n"); pr_err("ACPI call to get KBD function keys failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("KBD function keys not supported\n");
return -ENODEV; return -ENODEV;
}
return 0; return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
} }
static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode)
...@@ -1060,15 +985,12 @@ static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) ...@@ -1060,15 +985,12 @@ static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode)
result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { if (result == TOS_FAILURE)
pr_err("ACPI call to set KBD function keys failed\n"); pr_err("ACPI call to set KBD function keys failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("KBD function keys not supported\n");
return -ENODEV; return -ENODEV;
}
return 0; return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
} }
/* Panel Power ON */ /* Panel Power ON */
...@@ -1081,17 +1003,12 @@ static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) ...@@ -1081,17 +1003,12 @@ static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state)
result = sci_read(dev, SCI_PANEL_POWER_ON, state); result = sci_read(dev, SCI_PANEL_POWER_ON, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to get Panel Power ON failed\n"); pr_err("ACPI call to get Panel Power ON failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Panel Power on not supported\n");
return -ENODEV; return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state)
...@@ -1103,17 +1020,12 @@ static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) ...@@ -1103,17 +1020,12 @@ static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state)
result = sci_write(dev, SCI_PANEL_POWER_ON, state); result = sci_write(dev, SCI_PANEL_POWER_ON, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to set Panel Power ON failed\n"); pr_err("ACPI call to set Panel Power ON failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Panel Power ON not supported\n");
return -ENODEV; return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return result == TOS_SUCCESS ? 0 : -EIO;
} }
/* USB Three */ /* USB Three */
...@@ -1126,17 +1038,12 @@ static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) ...@@ -1126,17 +1038,12 @@ static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state)
result = sci_read(dev, SCI_USB_THREE, state); result = sci_read(dev, SCI_USB_THREE, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to get USB 3 failed\n"); pr_err("ACPI call to get USB 3 failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB 3 not supported\n");
return -ENODEV; return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
} }
static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
...@@ -1148,17 +1055,12 @@ static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) ...@@ -1148,17 +1055,12 @@ static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
result = sci_write(dev, SCI_USB_THREE, state); result = sci_write(dev, SCI_USB_THREE, state);
sci_close(dev); sci_close(dev);
if (result == TOS_FAILURE) { if (result == TOS_FAILURE)
pr_err("ACPI call to set USB 3 failed\n"); pr_err("ACPI call to set USB 3 failed\n");
return -EIO; else if (result == TOS_NOT_SUPPORTED)
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB 3 not supported\n");
return -ENODEV; return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0; return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
} }
/* Hotkey Event type */ /* Hotkey Event type */
...@@ -1172,35 +1074,39 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, ...@@ -1172,35 +1074,39 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev,
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
pr_err("ACPI call to get System type failed\n"); pr_err("ACPI call to get System type failed\n");
return -EIO;
} else if (out[0] == TOS_NOT_SUPPORTED) { } else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("System type not supported\n");
return -ENODEV; return -ENODEV;
} else if (out[0] == TOS_SUCCESS) {
*type = out[3];
return 0;
} }
*type = out[3]; return -EIO;
return 0;
} }
/* Transflective Backlight */ /* Transflective Backlight */
static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
{ {
u32 hci_result; u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status);
u32 status;
if (result == TOS_FAILURE)
pr_err("ACPI call to get Transflective Backlight failed\n");
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
hci_result = hci_read(dev, HCI_TR_BACKLIGHT, &status); return result == TOS_SUCCESS ? 0 : -EIO;
*enabled = !status;
return hci_result == TOS_SUCCESS ? 0 : -EIO;
} }
static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status)
{ {
u32 hci_result; u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status);
u32 value = !enable;
if (result == TOS_FAILURE)
pr_err("ACPI call to set Transflective Backlight failed\n");
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
hci_result = hci_write(dev, HCI_TR_BACKLIGHT, value); return result == TOS_SUCCESS ? 0 : -EIO;
return hci_result == TOS_SUCCESS ? 0 : -EIO;
} }
static struct proc_dir_entry *toshiba_proc_dir; static struct proc_dir_entry *toshiba_proc_dir;
...@@ -1208,23 +1114,26 @@ static struct proc_dir_entry *toshiba_proc_dir; ...@@ -1208,23 +1114,26 @@ static struct proc_dir_entry *toshiba_proc_dir;
/* LCD Brightness */ /* LCD Brightness */
static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
{ {
u32 hci_result; u32 result;
u32 value; u32 value;
int brightness = 0; int brightness = 0;
if (dev->tr_backlight_supported) { if (dev->tr_backlight_supported) {
bool enabled; int ret = get_tr_backlight_status(dev, &value);
int ret = get_tr_backlight_status(dev, &enabled);
if (ret) if (ret)
return ret; return ret;
if (enabled) if (value)
return 0; return 0;
brightness++; brightness++;
} }
hci_result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value);
if (hci_result == TOS_SUCCESS) if (result == TOS_FAILURE)
pr_err("ACPI call to get LCD Brightness failed\n");
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
if (result == TOS_SUCCESS)
return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
return -EIO; return -EIO;
...@@ -1240,8 +1149,8 @@ static int get_lcd_brightness(struct backlight_device *bd) ...@@ -1240,8 +1149,8 @@ static int get_lcd_brightness(struct backlight_device *bd)
static int lcd_proc_show(struct seq_file *m, void *v) static int lcd_proc_show(struct seq_file *m, void *v)
{ {
struct toshiba_acpi_dev *dev = m->private; struct toshiba_acpi_dev *dev = m->private;
int value;
int levels; int levels;
int value;
if (!dev->backlight_dev) if (!dev->backlight_dev)
return -ENODEV; return -ENODEV;
...@@ -1255,6 +1164,7 @@ static int lcd_proc_show(struct seq_file *m, void *v) ...@@ -1255,6 +1164,7 @@ static int lcd_proc_show(struct seq_file *m, void *v)
} }
pr_err("Error reading LCD brightness\n"); pr_err("Error reading LCD brightness\n");
return -EIO; return -EIO;
} }
...@@ -1265,11 +1175,10 @@ static int lcd_proc_open(struct inode *inode, struct file *file) ...@@ -1265,11 +1175,10 @@ static int lcd_proc_open(struct inode *inode, struct file *file)
static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
{ {
u32 hci_result; u32 result;
if (dev->tr_backlight_supported) { if (dev->tr_backlight_supported) {
bool enable = !value; int ret = set_tr_backlight_status(dev, !value);
int ret = set_tr_backlight_status(dev, enable);
if (ret) if (ret)
return ret; return ret;
...@@ -1278,8 +1187,13 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) ...@@ -1278,8 +1187,13 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
} }
value = value << HCI_LCD_BRIGHTNESS_SHIFT; value = value << HCI_LCD_BRIGHTNESS_SHIFT;
hci_result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); result = hci_write(dev, HCI_LCD_BRIGHTNESS, value);
return hci_result == TOS_SUCCESS ? 0 : -EIO; if (result == TOS_FAILURE)
pr_err("ACPI call to set LCD Brightness failed\n");
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
return result == TOS_SUCCESS ? 0 : -EIO;
} }
static int set_lcd_status(struct backlight_device *bd) static int set_lcd_status(struct backlight_device *bd)
...@@ -1295,24 +1209,22 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, ...@@ -1295,24 +1209,22 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
char cmd[42]; char cmd[42];
size_t len; size_t len;
int value;
int ret;
int levels = dev->backlight_dev->props.max_brightness + 1; int levels = dev->backlight_dev->props.max_brightness + 1;
int value;
len = min(count, sizeof(cmd) - 1); len = min(count, sizeof(cmd) - 1);
if (copy_from_user(cmd, buf, len)) if (copy_from_user(cmd, buf, len))
return -EFAULT; return -EFAULT;
cmd[len] = '\0'; cmd[len] = '\0';
if (sscanf(cmd, " brightness : %i", &value) == 1 && if (sscanf(cmd, " brightness : %i", &value) != 1 &&
value >= 0 && value < levels) { value < 0 && value > levels)
ret = set_lcd_brightness(dev, value); return -EINVAL;
if (ret == 0)
ret = count; if (set_lcd_brightness(dev, value))
} else { return -EIO;
ret = -EINVAL;
} return count;
return ret;
} }
static const struct file_operations lcd_proc_fops = { static const struct file_operations lcd_proc_fops = {
...@@ -1324,22 +1236,25 @@ static const struct file_operations lcd_proc_fops = { ...@@ -1324,22 +1236,25 @@ static const struct file_operations lcd_proc_fops = {
.write = lcd_proc_write, .write = lcd_proc_write,
}; };
/* Video-Out */
static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
{ {
u32 hci_result; u32 result = hci_read(dev, HCI_VIDEO_OUT, status);
if (result == TOS_FAILURE)
pr_err("ACPI call to get Video-Out failed\n");
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
hci_result = hci_read(dev, HCI_VIDEO_OUT, status); return result == TOS_SUCCESS ? 0 : -EIO;
return hci_result == TOS_SUCCESS ? 0 : -EIO;
} }
static int video_proc_show(struct seq_file *m, void *v) static int video_proc_show(struct seq_file *m, void *v)
{ {
struct toshiba_acpi_dev *dev = m->private; struct toshiba_acpi_dev *dev = m->private;
u32 value; u32 value;
int ret;
ret = get_video_status(dev, &value); if (!get_video_status(dev, &value)) {
if (!ret) {
int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
...@@ -1347,9 +1262,10 @@ static int video_proc_show(struct seq_file *m, void *v) ...@@ -1347,9 +1262,10 @@ static int video_proc_show(struct seq_file *m, void *v)
seq_printf(m, "lcd_out: %d\n", is_lcd); seq_printf(m, "lcd_out: %d\n", is_lcd);
seq_printf(m, "crt_out: %d\n", is_crt); seq_printf(m, "crt_out: %d\n", is_crt);
seq_printf(m, "tv_out: %d\n", is_tv); seq_printf(m, "tv_out: %d\n", is_tv);
return 0;
} }
return ret; return -EIO;
} }
static int video_proc_open(struct inode *inode, struct file *file) static int video_proc_open(struct inode *inode, struct file *file)
...@@ -1361,13 +1277,14 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, ...@@ -1361,13 +1277,14 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos) size_t count, loff_t *pos)
{ {
struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
char *cmd, *buffer; char *buffer;
int ret; char *cmd;
int value;
int remain = count; int remain = count;
int lcd_out = -1; int lcd_out = -1;
int crt_out = -1; int crt_out = -1;
int tv_out = -1; int tv_out = -1;
int value;
int ret;
u32 video_out; u32 video_out;
cmd = kmalloc(count + 1, GFP_KERNEL); cmd = kmalloc(count + 1, GFP_KERNEL);
...@@ -1419,7 +1336,7 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, ...@@ -1419,7 +1336,7 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
} }
return ret ? ret : count; return ret ? -EIO : count;
} }
static const struct file_operations video_proc_fops = { static const struct file_operations video_proc_fops = {
...@@ -1431,27 +1348,43 @@ static const struct file_operations video_proc_fops = { ...@@ -1431,27 +1348,43 @@ static const struct file_operations video_proc_fops = {
.write = video_proc_write, .write = video_proc_write,
}; };
/* Fan status */
static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
{ {
u32 hci_result; u32 result = hci_read(dev, HCI_FAN, status);
if (result == TOS_FAILURE)
pr_err("ACPI call to get Fan status failed\n");
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
hci_result = hci_read(dev, HCI_FAN, status); return result == TOS_SUCCESS ? 0 : -EIO;
return hci_result == TOS_SUCCESS ? 0 : -EIO; }
static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status)
{
u32 result = hci_write(dev, HCI_FAN, status);
if (result == TOS_FAILURE)
pr_err("ACPI call to set Fan status failed\n");
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
return result == TOS_SUCCESS ? 0 : -EIO;
} }
static int fan_proc_show(struct seq_file *m, void *v) static int fan_proc_show(struct seq_file *m, void *v)
{ {
struct toshiba_acpi_dev *dev = m->private; struct toshiba_acpi_dev *dev = m->private;
int ret;
u32 value; u32 value;
ret = get_fan_status(dev, &value); if (get_fan_status(dev, &value))
if (!ret) { return -EIO;
seq_printf(m, "running: %d\n", (value > 0));
seq_printf(m, "force_on: %d\n", dev->force_fan);
}
return ret; seq_printf(m, "running: %d\n", (value > 0));
seq_printf(m, "force_on: %d\n", dev->force_fan);
return 0;
} }
static int fan_proc_open(struct inode *inode, struct file *file) static int fan_proc_open(struct inode *inode, struct file *file)
...@@ -1466,23 +1399,20 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf, ...@@ -1466,23 +1399,20 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf,
char cmd[42]; char cmd[42];
size_t len; size_t len;
int value; int value;
u32 hci_result;
len = min(count, sizeof(cmd) - 1); len = min(count, sizeof(cmd) - 1);
if (copy_from_user(cmd, buf, len)) if (copy_from_user(cmd, buf, len))
return -EFAULT; return -EFAULT;
cmd[len] = '\0'; cmd[len] = '\0';
if (sscanf(cmd, " force_on : %i", &value) == 1 && if (sscanf(cmd, " force_on : %i", &value) != 1 &&
value >= 0 && value <= 1) { value != 0 && value != 1)
hci_result = hci_write(dev, HCI_FAN, value);
if (hci_result == TOS_SUCCESS)
dev->force_fan = value;
else
return -EIO;
} else {
return -EINVAL; return -EINVAL;
}
if (set_fan_status(dev, value))
return -EIO;
dev->force_fan = value;
return count; return count;
} }
...@@ -1499,32 +1429,10 @@ static const struct file_operations fan_proc_fops = { ...@@ -1499,32 +1429,10 @@ static const struct file_operations fan_proc_fops = {
static int keys_proc_show(struct seq_file *m, void *v) static int keys_proc_show(struct seq_file *m, void *v)
{ {
struct toshiba_acpi_dev *dev = m->private; struct toshiba_acpi_dev *dev = m->private;
u32 hci_result;
u32 value;
if (!dev->key_event_valid && dev->system_event_supported) {
hci_result = hci_read(dev, HCI_SYSTEM_EVENT, &value);
if (hci_result == TOS_SUCCESS) {
dev->key_event_valid = 1;
dev->last_key_event = value;
} else if (hci_result == TOS_FIFO_EMPTY) {
/* Better luck next time */
} else if (hci_result == TOS_NOT_SUPPORTED) {
/*
* This is a workaround for an unresolved issue on
* some machines where system events sporadically
* become disabled.
*/
hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1);
pr_notice("Re-enabled hotkeys\n");
} else {
pr_err("Error reading hotkey status\n");
return -EIO;
}
}
seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid);
seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event);
return 0; return 0;
} }
...@@ -1641,7 +1549,6 @@ static ssize_t fan_store(struct device *dev, ...@@ -1641,7 +1549,6 @@ static ssize_t fan_store(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 result;
int state; int state;
int ret; int ret;
...@@ -1652,11 +1559,9 @@ static ssize_t fan_store(struct device *dev, ...@@ -1652,11 +1559,9 @@ static ssize_t fan_store(struct device *dev,
if (state != 0 && state != 1) if (state != 0 && state != 1)
return -EINVAL; return -EINVAL;
result = hci_write(toshiba, HCI_FAN, state); ret = set_fan_status(toshiba, state);
if (result == TOS_FAILURE) if (ret)
return -EIO; return ret;
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
return count; return count;
} }
...@@ -1682,7 +1587,6 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, ...@@ -1682,7 +1587,6 @@ static ssize_t kbd_backlight_mode_store(struct device *dev,
{ {
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int mode; int mode;
int time;
int ret; int ret;
...@@ -1713,7 +1617,7 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, ...@@ -1713,7 +1617,7 @@ static ssize_t kbd_backlight_mode_store(struct device *dev,
/* Only make a change if the actual mode has changed */ /* Only make a change if the actual mode has changed */
if (toshiba->kbd_mode != mode) { if (toshiba->kbd_mode != mode) {
/* Shift the time to "base time" (0x3c0000 == 60 seconds) */ /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
time = toshiba->kbd_time << HCI_MISC_SHIFT; int time = toshiba->kbd_time << HCI_MISC_SHIFT;
/* OR the "base time" to the actual method format */ /* OR the "base time" to the actual method format */
if (toshiba->kbd_type == 1) { if (toshiba->kbd_type == 1) {
...@@ -2261,6 +2165,81 @@ static struct attribute_group toshiba_attr_group = { ...@@ -2261,6 +2165,81 @@ static struct attribute_group toshiba_attr_group = {
.attrs = toshiba_attributes, .attrs = toshiba_attributes,
}; };
/*
* Misc device
*/
static int toshiba_acpi_smm_bridge(SMMRegisters *regs)
{
u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx,
regs->edx, regs->esi, regs->edi };
u32 out[TCI_WORDS];
acpi_status status;
status = tci_raw(toshiba_acpi, in, out);
if (ACPI_FAILURE(status)) {
pr_err("ACPI call to query SMM registers failed\n");
return -EIO;
}
/* Fillout the SMM struct with the TCI call results */
regs->eax = out[0];
regs->ebx = out[1];
regs->ecx = out[2];
regs->edx = out[3];
regs->esi = out[4];
regs->edi = out[5];
return 0;
}
static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd,
unsigned long arg)
{
SMMRegisters __user *argp = (SMMRegisters __user *)arg;
SMMRegisters regs;
int ret;
if (!argp)
return -EINVAL;
switch (cmd) {
case TOSH_SMM:
if (copy_from_user(&regs, argp, sizeof(SMMRegisters)))
return -EFAULT;
ret = toshiba_acpi_smm_bridge(&regs);
if (ret)
return ret;
if (copy_to_user(argp, &regs, sizeof(SMMRegisters)))
return -EFAULT;
break;
case TOSHIBA_ACPI_SCI:
if (copy_from_user(&regs, argp, sizeof(SMMRegisters)))
return -EFAULT;
/* Ensure we are being called with a SCI_{GET, SET} register */
if (regs.eax != SCI_GET && regs.eax != SCI_SET)
return -EINVAL;
if (!sci_open(toshiba_acpi))
return -EIO;
ret = toshiba_acpi_smm_bridge(&regs);
sci_close(toshiba_acpi);
if (ret)
return ret;
if (copy_to_user(argp, &regs, sizeof(SMMRegisters)))
return -EFAULT;
break;
default:
return -EINVAL;
}
return 0;
}
static const struct file_operations toshiba_acpi_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = toshiba_acpi_ioctl,
.llseek = noop_llseek,
};
/* /*
* Hotkeys * Hotkeys
*/ */
...@@ -2361,22 +2340,28 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, ...@@ -2361,22 +2340,28 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
{ {
u32 hci_result, value;
int retries = 3;
int scancode;
if (dev->info_supported) { if (dev->info_supported) {
scancode = toshiba_acpi_query_hotkey(dev); int scancode = toshiba_acpi_query_hotkey(dev);
if (scancode < 0)
if (scancode < 0) {
pr_err("Failed to query hotkey event\n"); pr_err("Failed to query hotkey event\n");
else if (scancode != 0) } else if (scancode != 0) {
toshiba_acpi_report_hotkey(dev, scancode); toshiba_acpi_report_hotkey(dev, scancode);
dev->key_event_valid = 1;
dev->last_key_event = scancode;
}
} else if (dev->system_event_supported) { } else if (dev->system_event_supported) {
u32 result;
u32 value;
int retries = 3;
do { do {
hci_result = hci_read(dev, HCI_SYSTEM_EVENT, &value); result = hci_read(dev, HCI_SYSTEM_EVENT, &value);
switch (hci_result) { switch (result) {
case TOS_SUCCESS: case TOS_SUCCESS:
toshiba_acpi_report_hotkey(dev, (int)value); toshiba_acpi_report_hotkey(dev, (int)value);
dev->key_event_valid = 1;
dev->last_key_event = value;
break; break;
case TOS_NOT_SUPPORTED: case TOS_NOT_SUPPORTED:
/* /*
...@@ -2384,15 +2369,15 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) ...@@ -2384,15 +2369,15 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
* issue on some machines where system events * issue on some machines where system events
* sporadically become disabled. * sporadically become disabled.
*/ */
hci_result = result = hci_write(dev, HCI_SYSTEM_EVENT, 1);
hci_write(dev, HCI_SYSTEM_EVENT, 1); if (result == TOS_SUCCESS)
pr_notice("Re-enabled hotkeys\n"); pr_notice("Re-enabled hotkeys\n");
/* Fall through */ /* Fall through */
default: default:
retries--; retries--;
break; break;
} }
} while (retries && hci_result != TOS_FIFO_EMPTY); } while (retries && result != TOS_FIFO_EMPTY);
} }
} }
...@@ -2404,6 +2389,11 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) ...@@ -2404,6 +2389,11 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
u32 hci_result; u32 hci_result;
int error; int error;
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) {
pr_info("WMI event detected, hotkeys will not be monitored\n");
return 0;
}
error = toshiba_acpi_enable_hotkeys(dev); error = toshiba_acpi_enable_hotkeys(dev);
if (error) if (error)
return error; return error;
...@@ -2496,7 +2486,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) ...@@ -2496,7 +2486,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
struct backlight_properties props; struct backlight_properties props;
int brightness; int brightness;
int ret; int ret;
bool enabled;
/* /*
* Some machines don't support the backlight methods at all, and * Some machines don't support the backlight methods at all, and
...@@ -2513,10 +2502,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) ...@@ -2513,10 +2502,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
return 0; return 0;
} }
/* Determine whether or not BIOS supports transflective backlight */
ret = get_tr_backlight_status(dev, &enabled);
dev->tr_backlight_supported = !ret;
/* /*
* Tell acpi-video-detect code to prefer vendor backlight on all * Tell acpi-video-detect code to prefer vendor backlight on all
* systems with transflective backlight and on dmi matched systems. * systems with transflective backlight and on dmi matched systems.
...@@ -2552,10 +2537,52 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) ...@@ -2552,10 +2537,52 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
return 0; return 0;
} }
static void print_supported_features(struct toshiba_acpi_dev *dev)
{
pr_info("Supported laptop features:");
if (dev->hotkey_dev)
pr_cont(" hotkeys");
if (dev->backlight_dev)
pr_cont(" backlight");
if (dev->video_supported)
pr_cont(" video-out");
if (dev->fan_supported)
pr_cont(" fan");
if (dev->tr_backlight_supported)
pr_cont(" transflective-backlight");
if (dev->illumination_supported)
pr_cont(" illumination");
if (dev->kbd_illum_supported)
pr_cont(" keyboard-backlight");
if (dev->touchpad_supported)
pr_cont(" touchpad");
if (dev->eco_supported)
pr_cont(" eco-led");
if (dev->accelerometer_supported)
pr_cont(" accelerometer-axes");
if (dev->usb_sleep_charge_supported)
pr_cont(" usb-sleep-charge");
if (dev->usb_rapid_charge_supported)
pr_cont(" usb-rapid-charge");
if (dev->usb_sleep_music_supported)
pr_cont(" usb-sleep-music");
if (dev->kbd_function_keys_supported)
pr_cont(" special-function-keys");
if (dev->panel_power_on_supported)
pr_cont(" panel-power-on");
if (dev->usb_three_supported)
pr_cont(" usb3");
pr_cont("\n");
}
static int toshiba_acpi_remove(struct acpi_device *acpi_dev) static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
{ {
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
misc_deregister(&dev->miscdev);
remove_toshiba_proc_entries(dev); remove_toshiba_proc_entries(dev);
if (dev->sysfs_created) if (dev->sysfs_created)
...@@ -2574,13 +2601,13 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) ...@@ -2574,13 +2601,13 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
backlight_device_unregister(dev->backlight_dev); backlight_device_unregister(dev->backlight_dev);
if (dev->illumination_supported) if (dev->illumination_led_registered)
led_classdev_unregister(&dev->led_dev); led_classdev_unregister(&dev->led_dev);
if (dev->kbd_led_registered) if (dev->kbd_led_registered)
led_classdev_unregister(&dev->kbd_led); led_classdev_unregister(&dev->kbd_led);
if (dev->eco_supported) if (dev->eco_led_registered)
led_classdev_unregister(&dev->eco_led); led_classdev_unregister(&dev->eco_led);
if (toshiba_acpi) if (toshiba_acpi)
...@@ -2627,6 +2654,17 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ...@@ -2627,6 +2654,17 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
return -ENOMEM; return -ENOMEM;
dev->acpi_dev = acpi_dev; dev->acpi_dev = acpi_dev;
dev->method_hci = hci_method; dev->method_hci = hci_method;
dev->miscdev.minor = MISC_DYNAMIC_MINOR;
dev->miscdev.name = "toshiba_acpi";
dev->miscdev.fops = &toshiba_acpi_fops;
ret = misc_register(&dev->miscdev);
if (ret) {
pr_err("Failed to register miscdevice\n");
kfree(dev);
return ret;
}
acpi_dev->driver_data = dev; acpi_dev->driver_data = dev;
dev_set_drvdata(&acpi_dev->dev, dev); dev_set_drvdata(&acpi_dev->dev, dev);
...@@ -2643,29 +2681,35 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ...@@ -2643,29 +2681,35 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
if (toshiba_acpi_setup_keyboard(dev)) if (toshiba_acpi_setup_keyboard(dev))
pr_info("Unable to activate hotkeys\n"); pr_info("Unable to activate hotkeys\n");
/* Determine whether or not BIOS supports transflective backlight */
ret = get_tr_backlight_status(dev, &dummy);
dev->tr_backlight_supported = !ret;
ret = toshiba_acpi_setup_backlight(dev); ret = toshiba_acpi_setup_backlight(dev);
if (ret) if (ret)
goto error; goto error;
if (toshiba_illumination_available(dev)) { toshiba_illumination_available(dev);
if (dev->illumination_supported) {
dev->led_dev.name = "toshiba::illumination"; dev->led_dev.name = "toshiba::illumination";
dev->led_dev.max_brightness = 1; dev->led_dev.max_brightness = 1;
dev->led_dev.brightness_set = toshiba_illumination_set; dev->led_dev.brightness_set = toshiba_illumination_set;
dev->led_dev.brightness_get = toshiba_illumination_get; dev->led_dev.brightness_get = toshiba_illumination_get;
if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
dev->illumination_supported = 1; dev->illumination_led_registered = true;
} }
if (toshiba_eco_mode_available(dev)) { toshiba_eco_mode_available(dev);
if (dev->eco_supported) {
dev->eco_led.name = "toshiba::eco_mode"; dev->eco_led.name = "toshiba::eco_mode";
dev->eco_led.max_brightness = 1; dev->eco_led.max_brightness = 1;
dev->eco_led.brightness_set = toshiba_eco_mode_set_status; dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
dev->eco_led.brightness_get = toshiba_eco_mode_get_status; dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led))
dev->eco_supported = 1; dev->eco_led_registered = true;
} }
dev->kbd_illum_supported = toshiba_kbd_illum_available(dev); toshiba_kbd_illum_available(dev);
/* /*
* Only register the LED if KBD illumination is supported * Only register the LED if KBD illumination is supported
* and the keyboard backlight operation mode is set to FN-Z * and the keyboard backlight operation mode is set to FN-Z
...@@ -2676,14 +2720,13 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ...@@ -2676,14 +2720,13 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
dev->kbd_led_registered = 1; dev->kbd_led_registered = true;
} }
ret = toshiba_touchpad_get(dev, &dummy); ret = toshiba_touchpad_get(dev, &dummy);
dev->touchpad_supported = !ret; dev->touchpad_supported = !ret;
ret = toshiba_accelerometer_supported(dev); toshiba_accelerometer_available(dev);
dev->accelerometer_supported = !ret;
toshiba_usb_sleep_charge_available(dev); toshiba_usb_sleep_charge_available(dev);
...@@ -2705,6 +2748,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ...@@ -2705,6 +2748,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
ret = get_fan_status(dev, &dummy); ret = get_fan_status(dev, &dummy);
dev->fan_supported = !ret; dev->fan_supported = !ret;
print_supported_features(dev);
/* /*
* Enable the "Special Functions" mode only if they are * Enable the "Special Functions" mode only if they are
* supported and if they are activated. * supported and if they are activated.
...@@ -2738,6 +2783,14 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) ...@@ -2738,6 +2783,14 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
switch (event) { switch (event) {
case 0x80: /* Hotkeys and some system events */ case 0x80: /* Hotkeys and some system events */
/*
* Machines with this WMI GUID aren't supported due to bugs in
* their AML.
*
* Return silently to avoid triggering a netlink event.
*/
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
return;
toshiba_acpi_process_hotkeys(dev); toshiba_acpi_process_hotkeys(dev);
break; break;
case 0x81: /* Dock events */ case 0x81: /* Dock events */
...@@ -2781,10 +2834,14 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) ...@@ -2781,10 +2834,14 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
static int toshiba_acpi_suspend(struct device *device) static int toshiba_acpi_suspend(struct device *device)
{ {
struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
u32 result;
if (dev->hotkey_dev) if (dev->hotkey_dev) {
u32 result;
result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE);
if (result != TOS_SUCCESS)
pr_info("Unable to disable hotkeys\n");
}
return 0; return 0;
} }
...@@ -2792,10 +2849,10 @@ static int toshiba_acpi_suspend(struct device *device) ...@@ -2792,10 +2849,10 @@ static int toshiba_acpi_suspend(struct device *device)
static int toshiba_acpi_resume(struct device *device) static int toshiba_acpi_resume(struct device *device)
{ {
struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
int error;
if (dev->hotkey_dev) { if (dev->hotkey_dev) {
error = toshiba_acpi_enable_hotkeys(dev); int error = toshiba_acpi_enable_hotkeys(dev);
if (error) if (error)
pr_info("Unable to re-enable hotkeys\n"); pr_info("Unable to re-enable hotkeys\n");
} }
...@@ -2824,14 +2881,6 @@ static int __init toshiba_acpi_init(void) ...@@ -2824,14 +2881,6 @@ static int __init toshiba_acpi_init(void)
{ {
int ret; int ret;
/*
* Machines with this WMI guid aren't supported due to bugs in
* their AML. This check relies on wmi initializing before
* toshiba_acpi to guarantee guids have been identified.
*/
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
return -ENODEV;
toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
if (!toshiba_proc_dir) { if (!toshiba_proc_dir) {
pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
......
/* toshiba.h -- Linux driver for accessing the SMM on Toshiba laptops /* toshiba.h -- Linux driver for accessing the SMM on Toshiba laptops
* *
* Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk)
* Copyright (c) 2015 Azael Avalos <coproscefalo@gmail.com>
* *
* Thanks to Juergen Heinzl <juergen@monocerus.demon.co.uk> for the pointers * Thanks to Juergen Heinzl <juergen@monocerus.demon.co.uk> for the pointers
* on making sure the structure is aligned and packed. * on making sure the structure is aligned and packed.
...@@ -20,9 +21,18 @@ ...@@ -20,9 +21,18 @@
#ifndef _UAPI_LINUX_TOSHIBA_H #ifndef _UAPI_LINUX_TOSHIBA_H
#define _UAPI_LINUX_TOSHIBA_H #define _UAPI_LINUX_TOSHIBA_H
#define TOSH_PROC "/proc/toshiba" /*
#define TOSH_DEVICE "/dev/toshiba" * Toshiba modules paths
#define TOSH_SMM _IOWR('t', 0x90, int) /* broken: meant 24 bytes */ */
#define TOSH_PROC "/proc/toshiba"
#define TOSH_DEVICE "/dev/toshiba"
#define TOSHIBA_ACPI_PROC "/proc/acpi/toshiba"
#define TOSHIBA_ACPI_DEVICE "/dev/toshiba_acpi"
/*
* Toshiba SMM structure
*/
typedef struct { typedef struct {
unsigned int eax; unsigned int eax;
...@@ -33,5 +43,21 @@ typedef struct { ...@@ -33,5 +43,21 @@ typedef struct {
unsigned int edi __attribute__ ((packed)); unsigned int edi __attribute__ ((packed));
} SMMRegisters; } SMMRegisters;
/*
* IOCTLs (0x90 - 0x91)
*/
#define TOSH_SMM _IOWR('t', 0x90, SMMRegisters)
/*
* Convenience toshiba_acpi command.
*
* The System Configuration Interface (SCI) is opened/closed internally
* to avoid userspace of buggy BIOSes.
*
* The toshiba_acpi module checks whether the eax register is set with
* SCI_GET (0xf300) or SCI_SET (0xf400), returning -EINVAL if not.
*/
#define TOSHIBA_ACPI_SCI _IOWR('t', 0x91, SMMRegisters)
#endif /* _UAPI_LINUX_TOSHIBA_H */ #endif /* _UAPI_LINUX_TOSHIBA_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment