Commit 605f884d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86

Pull x86 platform driver updates from Matthew Garrett:
 "A moderate number of changes, but nothing awfully significant.

  A lot of const cleanups, some reworking and additions to the rfkill
  quirks in the asus driver, a new driver for generating falling laptop
  events on Toshibas and some misc fixes.

  Maybe vendors have stopped inventing things"

* 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (41 commits)
  platform/x86: Enable build support for toshiba_haps
  Documentation: Add file about toshiba_haps module
  platform/x86: Toshiba HDD Active Protection Sensor
  asus-nb-wmi: Add wapf4 quirk for the U32U
  alienware-wmi: make hdmi_mux enabled on case-by-case basis
  ideapad-laptop: Constify DMI table and other r/o variables
  asus-nb-wmi.c: Rename x401u quirk to wapf4
  compal-laptop: correct invalid hwmon name
  toshiba_acpi: Add Qosmio X75-A to the alt keymap dmi list
  toshiba_acpi: Add extra check to backlight code
  Fix log message about future removal of interface
  ideapad-laptop: Disable touchpad interface on Yoga models
  asus-nb-wmi: Add wapf4 quirk for the X550CC
  intel_ips: Make ips_mcp_limits variables static
  thinkpad_acpi: Mark volume_alsa_control_{vol,mute} as __initdata
  fujitsu-laptop: Mark fujitsu_dmi_table[] DMI table as __initconst
  hp-wmi: Add missing __init annotations to initialization code
  hp_accel: Constify ACPI and DMI tables
  fujitsu-tablet: Mark DMI callbacks as __init code
  dell-laptop: Mark dell_quirks[] DMI table as __initconst
  ...
parents 49899007 186e4e89
......@@ -18,3 +18,5 @@ sonypi.txt
- info on Linux Sony Programmable I/O Device support.
thinkpad-acpi.txt
- information on the (IBM and Lenovo) ThinkPad ACPI Extras driver.
toshiba_haps.txt
- information on the Toshiba HDD Active Protection Sensor driver.
Kernel driver toshiba_haps
Toshiba HDD Active Protection Sensor
====================================
Author: Azael Avalos <coproscefalo@gmail.com>
0. Contents
-----------
1. Description
2. Interface
3. Accelerometer axes
4. Supported devices
5. Usage
1. Description
--------------
This driver provides support for the accelerometer found in various Toshiba
laptops, being called "Toshiba HDD Protection - Shock Sensor" officialy,
and detects laptops automatically with this device.
On Windows, Toshiba provided software monitors this device and provides
automatic HDD protection (head unload) on sudden moves or harsh vibrations,
however, this driver only provides a notification via a sysfs file to let
userspace tools or daemons act accordingly, as well as providing a sysfs
file to set the desired protection level or sensor sensibility.
2. Interface
------------
This device comes with 3 methods:
_STA - Checks existence of the device, returning Zero if the device does not
exists or is not supported.
PTLV - Sets the desired protection level.
RSSS - Shuts down the HDD protection interface for a few seconds,
then restores normal operation.
Note:
The presence of Solid State Drives (SSD) can make this driver to fail loading,
given the fact that such drives have no movable parts, and thus, not requiring
any "protection" as well as failing during the evaluation of the _STA method
found under this device.
3. Accelerometer axes
---------------------
This device does not report any axes, however, to query the sensor position
a couple HCI (Hardware Configuration Interface) calls (0x6D and 0xA6) are
provided to query such information, handled by the kernel module toshiba_acpi
since kernel version 3.15.
4. Supported devices
--------------------
This driver binds itself to the ACPI device TOS620A, and any Toshiba laptop
with this device is supported, given the fact that they have the presence of
conventional HDD and not only SSD, or a combination of both HDD and SSD.
5. Usage
--------
The sysfs files under /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS620A:00/ are:
protection_level - The protection_level is readable and writeable, and
provides a way to let userspace query the current protection
level, as well as set the desired protection level, the
available protection levels are:
0 - Disabled | 1 - Low | 2 - Medium | 3 - High
reset_protection - The reset_protection entry is writeable only, being "1"
the only parameter it accepts, it is used to trigger
a reset of the protection interface.
......@@ -10017,7 +10017,7 @@ F: arch/x86/
X86 PLATFORM DRIVERS
M: Matthew Garrett <matthew.garrett@nebula.com>
L: platform-driver-x86@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git
T: git git://cavan.codon.org.uk/platform-drivers-x86.git
S: Maintained
F: drivers/platform/x86/
......
......@@ -652,6 +652,25 @@ config TOSHIBA_BT_RFKILL
If you have a modern Toshiba laptop with a Bluetooth and an
RFKill switch (such as the Portege R500), say Y.
config TOSHIBA_HAPS
tristate "Toshiba HDD Active Protection Sensor"
depends on ACPI
---help---
This driver adds support for the built-in accelerometer
found on recent Toshiba laptops equiped with HID TOS620A
device.
This driver receives ACPI notify events 0x80 when the sensor
detects a sudden move or a harsh vibration, as well as an
ACPI notify event 0x81 whenever the movement or vibration has
been stabilized.
Also provides sysfs entries to get/set the desired protection
level and reseting the HDD protection interface.
If you have a recent Toshiba laptop with a built-in accelerometer
device, say Y.
config ACPI_CMPC
tristate "CMPC Laptop Extras"
depends on X86 && ACPI
......
......@@ -38,6 +38,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o
obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
......
......@@ -96,7 +96,7 @@ enum acer_wmi_event_ids {
WMID_ACCEL_EVENT = 0x5,
};
static const struct key_entry acer_wmi_keymap[] = {
static const struct key_entry acer_wmi_keymap[] __initconst = {
{KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */
{KE_KEY, 0x03, {KEY_WLAN} }, /* WiFi */
{KE_KEY, 0x04, {KEY_WLAN} }, /* WiFi */
......@@ -294,7 +294,7 @@ struct quirk_entry {
static struct quirk_entry *quirks;
static void set_quirks(void)
static void __init set_quirks(void)
{
if (!interface)
return;
......@@ -306,7 +306,7 @@ static void set_quirks(void)
interface->capability |= ACER_CAP_BRIGHTNESS;
}
static int dmi_matched(const struct dmi_system_id *dmi)
static int __init dmi_matched(const struct dmi_system_id *dmi)
{
quirks = dmi->driver_data;
return 1;
......@@ -337,7 +337,7 @@ static struct quirk_entry quirk_lenovo_ideapad_s205 = {
};
/* The Aspire One has a dummy ACPI-WMI interface - disable it */
static struct dmi_system_id acer_blacklist[] = {
static const struct dmi_system_id acer_blacklist[] __initconst = {
{
.ident = "Acer Aspire One (SSD)",
.matches = {
......@@ -355,7 +355,7 @@ static struct dmi_system_id acer_blacklist[] = {
{}
};
static struct dmi_system_id acer_quirks[] = {
static const struct dmi_system_id acer_quirks[] __initconst = {
{
.callback = dmi_matched,
.ident = "Acer Aspire 1360",
......@@ -530,14 +530,15 @@ static struct dmi_system_id acer_quirks[] = {
{}
};
static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
static int __init
video_set_backlight_video_vendor(const struct dmi_system_id *d)
{
interface->capability &= ~ACER_CAP_BRIGHTNESS;
pr_info("Brightness must be controlled by generic video driver\n");
return 0;
}
static const struct dmi_system_id video_vendor_dmi_table[] = {
static const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
{
.callback = video_set_backlight_video_vendor,
.ident = "Acer TravelMate 4750",
......@@ -582,7 +583,7 @@ static const struct dmi_system_id video_vendor_dmi_table[] = {
};
/* Find which quirks are needed for a particular vendor/ model pair */
static void find_quirks(void)
static void __init find_quirks(void)
{
if (!force_series) {
dmi_check_system(acer_quirks);
......@@ -749,7 +750,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap)
return wmab_execute(&args, NULL);
}
static acpi_status AMW0_find_mailled(void)
static acpi_status __init AMW0_find_mailled(void)
{
struct wmab_args args;
struct wmab_ret ret;
......@@ -781,16 +782,16 @@ static acpi_status AMW0_find_mailled(void)
return AE_OK;
}
static int AMW0_set_cap_acpi_check_device_found;
static int AMW0_set_cap_acpi_check_device_found __initdata;
static acpi_status AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
static acpi_status __init AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
u32 level, void *context, void **retval)
{
AMW0_set_cap_acpi_check_device_found = 1;
return AE_OK;
}
static const struct acpi_device_id norfkill_ids[] = {
static const struct acpi_device_id norfkill_ids[] __initconst = {
{ "VPC2004", 0},
{ "IBM0068", 0},
{ "LEN0068", 0},
......@@ -798,7 +799,7 @@ static const struct acpi_device_id norfkill_ids[] = {
{ "", 0},
};
static int AMW0_set_cap_acpi_check_device(void)
static int __init AMW0_set_cap_acpi_check_device(void)
{
const struct acpi_device_id *id;
......@@ -808,7 +809,7 @@ static int AMW0_set_cap_acpi_check_device(void)
return AMW0_set_cap_acpi_check_device_found;
}
static acpi_status AMW0_set_capabilities(void)
static acpi_status __init AMW0_set_capabilities(void)
{
struct wmab_args args;
struct wmab_ret ret;
......@@ -1184,7 +1185,7 @@ static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
return wmid3_set_device_status(value, device);
}
static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
{
struct hotkey_function_type_aa *type_aa;
......@@ -1209,7 +1210,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
commun_fn_key_number = type_aa->commun_fn_key_number;
}
static acpi_status WMID_set_capabilities(void)
static acpi_status __init WMID_set_capabilities(void)
{
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *obj;
......@@ -1658,7 +1659,7 @@ static ssize_t show_bool_threeg(struct device *dev,
u32 result; \
acpi_status status;
pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
current->comm);
status = get_u32(&result, ACER_CAP_THREEG);
if (ACPI_SUCCESS(status))
......@@ -1671,7 +1672,7 @@ static ssize_t set_bool_threeg(struct device *dev,
{
u32 tmp = simple_strtoul(buf, NULL, 10);
acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
current->comm);
if (ACPI_FAILURE(status))
return -EINVAL;
......@@ -1683,7 +1684,7 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf)
{
pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
pr_info("This interface sysfs will be removed in 2014 - used by: %s\n",
current->comm);
switch (interface->type) {
case ACER_AMW0:
......@@ -1777,7 +1778,7 @@ static void acer_wmi_notify(u32 value, void *context)
}
}
static acpi_status
static acpi_status __init
wmid3_set_lm_mode(struct lm_input_params *params,
struct lm_return_value *return_value)
{
......@@ -1811,7 +1812,7 @@ wmid3_set_lm_mode(struct lm_input_params *params,
return status;
}
static int acer_wmi_enable_ec_raw(void)
static int __init acer_wmi_enable_ec_raw(void)
{
struct lm_return_value return_value;
acpi_status status;
......@@ -1834,7 +1835,7 @@ static int acer_wmi_enable_ec_raw(void)
return status;
}
static int acer_wmi_enable_lm(void)
static int __init acer_wmi_enable_lm(void)
{
struct lm_return_value return_value;
acpi_status status;
......@@ -2043,6 +2044,7 @@ static int acer_platform_remove(struct platform_device *device)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int acer_suspend(struct device *dev)
{
u32 value;
......@@ -2083,6 +2085,10 @@ static int acer_resume(struct device *dev)
return 0;
}
#else
#define acer_suspend NULL
#define acer_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
......@@ -2120,7 +2126,7 @@ static int remove_sysfs(struct platform_device *device)
return 0;
}
static int create_sysfs(void)
static int __init create_sysfs(void)
{
int retval = -ENOMEM;
......@@ -2149,7 +2155,7 @@ static void remove_debugfs(void)
debugfs_remove(interface->debug.root);
}
static int create_debugfs(void)
static int __init create_debugfs(void)
{
interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
if (!interface->debug.root) {
......
......@@ -59,25 +59,33 @@ enum WMAX_CONTROL_STATES {
struct quirk_entry {
u8 num_zones;
u8 hdmi_mux;
};
static struct quirk_entry *quirks;
static struct quirk_entry quirk_unknown = {
.num_zones = 2,
.hdmi_mux = 0,
};
static struct quirk_entry quirk_x51_family = {
.num_zones = 3,
.hdmi_mux = 0.
};
static int dmi_matched(const struct dmi_system_id *dmi)
static struct quirk_entry quirk_asm100 = {
.num_zones = 2,
.hdmi_mux = 1,
};
static int __init dmi_matched(const struct dmi_system_id *dmi)
{
quirks = dmi->driver_data;
return 1;
}
static struct dmi_system_id alienware_quirks[] = {
static const struct dmi_system_id alienware_quirks[] __initconst = {
{
.callback = dmi_matched,
.ident = "Alienware X51 R1",
......@@ -96,6 +104,15 @@ static struct dmi_system_id alienware_quirks[] = {
},
.driver_data = &quirk_x51_family,
},
{
.callback = dmi_matched,
.ident = "Alienware ASM100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"),
},
.driver_data = &quirk_asm100,
},
{}
};
......@@ -537,7 +554,8 @@ static struct attribute_group hdmi_attribute_group = {
static void remove_hdmi(struct platform_device *dev)
{
sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group);
if (quirks->hdmi_mux > 0)
sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group);
}
static int create_hdmi(struct platform_device *dev)
......@@ -583,7 +601,7 @@ static int __init alienware_wmi_init(void)
if (ret)
goto fail_platform_device2;
if (interface == WMAX) {
if (quirks->hdmi_mux > 0) {
ret = create_hdmi(platform_device);
if (ret)
goto fail_prep_hdmi;
......
......@@ -70,17 +70,35 @@ static struct quirk_entry quirk_asus_x55u = {
.no_display_toggle = true,
};
static struct quirk_entry quirk_asus_x401u = {
static struct quirk_entry quirk_asus_wapf4 = {
.wapf = 4,
};
static struct quirk_entry quirk_asus_x200ca = {
.wapf = 2,
};
static int dmi_matched(const struct dmi_system_id *dmi)
{
quirks = dmi->driver_data;
return 1;
}
static struct dmi_system_id asus_quirks[] = {
static const struct dmi_system_id asus_quirks[] = {
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. U32U",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "U32U"),
},
/*
* Note this machine has a Brazos APU, and most Brazos Asus
* machines need quirk_asus_x55u / wmi_backlight_power but
* here acpi-video seems to work fine for backlight control.
*/
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X401U",
......@@ -97,7 +115,7 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X401A"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -106,7 +124,7 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -124,7 +142,7 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X501A"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -133,7 +151,7 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -142,7 +160,25 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X550CC",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X550CC"),
},
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X550CL",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X550CL"),
},
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -151,7 +187,7 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X55A"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -160,7 +196,7 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X55C"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -178,7 +214,7 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -187,7 +223,16 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X75A"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X75VBP",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X75VBP"),
},
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -196,7 +241,7 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1015E"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
......@@ -205,7 +250,16 @@ static struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1015U"),
},
.driver_data = &quirk_asus_x401u,
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X200CA",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X200CA"),
},
.driver_data = &quirk_asus_x200ca,
},
{},
};
......
......@@ -46,6 +46,7 @@
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <acpi/video.h>
#include "asus-wmi.h"
......@@ -554,7 +555,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
goto error;
}
if (wlan_led_presence(asus) && (asus->driver->quirks->wapf == 4)) {
if (wlan_led_presence(asus) && (asus->driver->quirks->wapf > 0)) {
INIT_WORK(&asus->wlan_led_work, wlan_led_update);
asus->wlan_led.name = "asus::wlan";
......@@ -884,7 +885,7 @@ static int asus_new_rfkill(struct asus_wmi *asus,
return -EINVAL;
if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
(asus->driver->quirks->wapf == 4))
(asus->driver->quirks->wapf > 0))
rfkill_set_led_trigger_name(*rfkill, "asus-wlan");
rfkill_init_sw_state(*rfkill, !result);
......@@ -1270,10 +1271,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
int power;
max = read_brightness_max(asus);
if (max == -ENODEV)
max = 0;
else if (max < 0)
if (max < 0)
return max;
power = read_backlight_power(asus);
......@@ -1734,6 +1732,7 @@ static int asus_wmi_add(struct platform_device *pdev)
struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
struct asus_wmi *asus;
const char *chassis_type;
acpi_status status;
int err;
u32 result;
......@@ -1770,6 +1769,11 @@ static int asus_wmi_add(struct platform_device *pdev)
if (err)
goto fail_rfkill;
/* Some Asus desktop boards export an acpi-video backlight interface,
stop this from showing up */
chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
if (chassis_type && !strcmp(chassis_type, "3"))
acpi_video_dmi_promote_vendor();
if (asus->driver->quirks->wmi_backlight_power)
acpi_video_dmi_promote_vendor();
if (!acpi_video_backlight_support()) {
......
......@@ -1028,7 +1028,7 @@ static int compal_probe(struct platform_device *pdev)
return err;
hwmon_dev = hwmon_device_register_with_groups(&pdev->dev,
DRIVER_NAME, data,
"compal", data,
compal_hwmon_groups);
if (IS_ERR(hwmon_dev)) {
err = PTR_ERR(hwmon_dev);
......
......@@ -70,7 +70,7 @@ static struct quirk_entry quirk_dell_vostro_v130 = {
.touchpad_led = 1,
};
static int dmi_matched(const struct dmi_system_id *dmi)
static int __init dmi_matched(const struct dmi_system_id *dmi)
{
quirks = dmi->driver_data;
return 1;
......@@ -123,7 +123,7 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
};
MODULE_DEVICE_TABLE(dmi, dell_device_table);
static struct dmi_system_id dell_quirks[] = {
static const struct dmi_system_id dell_quirks[] __initconst = {
{
.callback = dmi_matched,
.ident = "Dell Vostro V130",
......@@ -780,7 +780,7 @@ static struct led_classdev touchpad_led = {
.flags = LED_CORE_SUSPENDRESUME,
};
static int touchpad_led_init(struct device *dev)
static int __init touchpad_led_init(struct device *dev)
{
return led_classdev_register(dev, &touchpad_led);
}
......
......@@ -1053,20 +1053,20 @@ static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
return sprintf(buf, "%d\n", get());
}
#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _get, _set) \
static ssize_t show_##_name(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
return show_sys_hwmon(_set, buf); \
return show_sys_hwmon(_get, buf); \
} \
static ssize_t store_##_name(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
return store_sys_hwmon(_get, buf, count); \
return store_sys_hwmon(_set, buf, count); \
} \
static DEVICE_ATTR(_name, _mode, show_##_name, store_##_name);
static DEVICE_ATTR(_name, _mode, show_##_name, store_##_name)
EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
......
......@@ -145,7 +145,7 @@ static int dmi_matched(const struct dmi_system_id *dmi)
return 1;
}
static struct dmi_system_id asus_quirks[] = {
static const struct dmi_system_id asus_quirks[] = {
{
.callback = dmi_matched,
.ident = "ASUSTeK Computer INC. 1000H",
......
......@@ -129,15 +129,14 @@
#define FUJLAPTOP_DBG_INFO 0x0004
#define FUJLAPTOP_DBG_TRACE 0x0008
#define dbg_printk(a_dbg_level, format, arg...) \
#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
#define vdbg_printk(a_dbg_level, format, arg...) \
do { if (dbg_level & a_dbg_level) \
printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
} while (0)
#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
#define vdbg_printk(a_dbg_level, format, arg...) \
dbg_printk(a_dbg_level, format, ## arg)
#else
#define vdbg_printk(a_dbg_level, format, arg...)
#define vdbg_printk(a_dbg_level, format, arg...) \
do { } while (0)
#endif
/* Device controlling the backlight and associated keys */
......@@ -564,7 +563,7 @@ static struct platform_driver fujitsupf_driver = {
}
};
static void dmi_check_cb_common(const struct dmi_system_id *id)
static void __init dmi_check_cb_common(const struct dmi_system_id *id)
{
pr_info("Identified laptop model '%s'\n", id->ident);
if (use_alt_lcd_levels == -1) {
......@@ -578,7 +577,7 @@ static void dmi_check_cb_common(const struct dmi_system_id *id)
}
}
static int dmi_check_cb_s6410(const struct dmi_system_id *id)
static int __init dmi_check_cb_s6410(const struct dmi_system_id *id)
{
dmi_check_cb_common(id);
fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
......@@ -586,7 +585,7 @@ static int dmi_check_cb_s6410(const struct dmi_system_id *id)
return 1;
}
static int dmi_check_cb_s6420(const struct dmi_system_id *id)
static int __init dmi_check_cb_s6420(const struct dmi_system_id *id)
{
dmi_check_cb_common(id);
fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
......@@ -594,7 +593,7 @@ static int dmi_check_cb_s6420(const struct dmi_system_id *id)
return 1;
}
static int dmi_check_cb_p8010(const struct dmi_system_id *id)
static int __init dmi_check_cb_p8010(const struct dmi_system_id *id)
{
dmi_check_cb_common(id);
fujitsu->keycode1 = KEY_HELP; /* "Support" */
......@@ -603,7 +602,7 @@ static int dmi_check_cb_p8010(const struct dmi_system_id *id)
return 1;
}
static struct dmi_system_id fujitsu_dmi_table[] = {
static const struct dmi_system_id fujitsu_dmi_table[] __initconst = {
{
.ident = "Fujitsu Siemens S6410",
.matches = {
......
......@@ -315,21 +315,21 @@ static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void fujitsu_dmi_common(const struct dmi_system_id *dmi)
static void __init fujitsu_dmi_common(const struct dmi_system_id *dmi)
{
pr_info("%s\n", dmi->ident);
memcpy(fujitsu.config.keymap, dmi->driver_data,
sizeof(fujitsu.config.keymap));
}
static int fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
static int __init fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
{
fujitsu_dmi_common(dmi);
fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
return 1;
}
static int fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
static int __init fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
{
fujitsu_dmi_common(dmi);
fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
......
......@@ -295,7 +295,7 @@ static int hp_wmi_tablet_state(void)
return (state & 0x4) ? 1 : 0;
}
static int hp_wmi_bios_2009_later(void)
static int __init hp_wmi_bios_2009_later(void)
{
int state = 0;
int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state,
......@@ -704,7 +704,7 @@ static void cleanup_sysfs(struct platform_device *device)
device_remove_file(&device->dev, &dev_attr_postcode);
}
static int hp_wmi_rfkill_setup(struct platform_device *device)
static int __init hp_wmi_rfkill_setup(struct platform_device *device)
{
int err;
int wireless = 0;
......@@ -806,7 +806,7 @@ static int hp_wmi_rfkill_setup(struct platform_device *device)
return err;
}
static int hp_wmi_rfkill2_setup(struct platform_device *device)
static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
{
int err, i;
struct bios_rfkill2_state state;
......
......@@ -74,7 +74,7 @@ static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
/* HP-specific accelerometer driver ------------------------------------ */
/* For automatic insertion of the module */
static struct acpi_device_id lis3lv02d_device_ids[] = {
static const struct acpi_device_id lis3lv02d_device_ids[] = {
{"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
{"HPQ6000", 0}, /* HP Mobile Data Protection System PNP */
{"HPQ6007", 0}, /* HP Mobile Data Protection System PNP */
......@@ -192,7 +192,7 @@ DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
}, \
.driver_data = &lis3lv02d_axis_##_axis \
}
static struct dmi_system_id lis3lv02d_dmi_ids[] = {
static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
/* product names are truncated to match all kinds of a same model */
AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
......
......@@ -87,6 +87,8 @@ struct ideapad_private {
struct backlight_device *blightdev;
struct dentry *debug;
unsigned long cfg;
bool has_hw_rfkill_switch;
bool has_touchpad_control;
};
static bool no_bt_rfkill;
......@@ -439,7 +441,7 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
return supported ? attr->mode : 0;
}
static struct attribute_group ideapad_attribute_group = {
static const struct attribute_group ideapad_attribute_group = {
.is_visible = ideapad_is_visible,
.attrs = ideapad_attributes
};
......@@ -454,7 +456,7 @@ struct ideapad_rfk_data {
int type;
};
const struct ideapad_rfk_data ideapad_rfk_data[] = {
const const struct ideapad_rfk_data ideapad_rfk_data[] = {
{ "ideapad_wlan", CFG_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
{ "ideapad_bluetooth", CFG_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
{ "ideapad_3g", CFG_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
......@@ -473,12 +475,14 @@ static struct rfkill_ops ideapad_rfk_ops = {
static void ideapad_sync_rfk_state(struct ideapad_private *priv)
{
unsigned long hw_blocked;
unsigned long hw_blocked = 0;
int i;
if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
return;
hw_blocked = !hw_blocked;
if (priv->has_hw_rfkill_switch) {
if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
return;
hw_blocked = !hw_blocked;
}
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
if (priv->rfk[i])
......@@ -763,6 +767,9 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
{
unsigned long value;
if (!priv->has_touchpad_control)
return;
/* Without reading from EC touchpad LED doesn't switch state */
if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
/* Some IdeaPads don't really turn off touchpad - they only
......@@ -821,14 +828,39 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
}
}
/* Blacklist for devices where the ideapad rfkill interface does not work */
static struct dmi_system_id rfkill_blacklist[] = {
/* The Lenovo Yoga 2 11 always reports everything as blocked */
/*
* Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF
* always results in 0 on these models, causing ideapad_laptop to wrongly
* report all radios as hardware-blocked.
*/
static struct dmi_system_id no_hw_rfkill_list[] = {
{
.ident = "Lenovo Yoga 2 11",
.ident = "Lenovo Yoga 2 11 / 13 / Pro",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
},
},
{}
};
/*
* Some models don't offer touchpad ctrl through the ideapad interface, causing
* ideapad_sync_touchpad_state to send wrong touchpad enable/disable events.
*/
static struct dmi_system_id no_touchpad_ctrl_list[] = {
{
.ident = "Lenovo Yoga 1 series",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga"),
},
},
{
.ident = "Lenovo Yoga 2 11 / 13 / Pro",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
},
},
{}
......@@ -856,6 +888,8 @@ static int ideapad_acpi_add(struct platform_device *pdev)
priv->cfg = cfg;
priv->adev = adev;
priv->platform_device = pdev;
priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list);
priv->has_touchpad_control = !dmi_check_system(no_touchpad_ctrl_list);
ret = ideapad_sysfs_init(priv);
if (ret)
......@@ -869,11 +903,17 @@ static int ideapad_acpi_add(struct platform_device *pdev)
if (ret)
goto input_failed;
if (!dmi_check_system(rfkill_blacklist)) {
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
ideapad_register_rfkill(priv, i);
}
/*
* On some models without a hw-switch (the yoga 2 13 at least)
* VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
*/
if (!priv->has_hw_rfkill_switch)
write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
ideapad_register_rfkill(priv, i);
ideapad_sync_rfk_state(priv);
ideapad_sync_touchpad_state(priv);
......
......@@ -269,7 +269,7 @@ struct ips_mcp_limits {
/* Max temps are -10 degrees C to avoid PROCHOT# */
struct ips_mcp_limits ips_sv_limits = {
static struct ips_mcp_limits ips_sv_limits = {
.mcp_power_limit = 35000,
.core_power_limit = 29000,
.mch_power_limit = 20000,
......@@ -277,7 +277,7 @@ struct ips_mcp_limits ips_sv_limits = {
.mch_temp_limit = 90
};
struct ips_mcp_limits ips_lv_limits = {
static struct ips_mcp_limits ips_lv_limits = {
.mcp_power_limit = 25000,
.core_power_limit = 21000,
.mch_power_limit = 13000,
......@@ -285,7 +285,7 @@ struct ips_mcp_limits ips_lv_limits = {
.mch_temp_limit = 90
};
struct ips_mcp_limits ips_ulv_limits = {
static struct ips_mcp_limits ips_ulv_limits = {
.mcp_power_limit = 18000,
.core_power_limit = 14000,
.mch_power_limit = 11000,
......
......@@ -2389,7 +2389,7 @@ static int sony_nc_lid_resume_setup(struct platform_device *pd,
lid_ctl->attrs[LID_RESUME_S3].store = sony_nc_lid_resume_store;
}
for (i = 0; i < LID_RESUME_MAX &&
lid_ctl->attrs[LID_RESUME_S3].attr.name; i++) {
lid_ctl->attrs[i].attr.name; i++) {
result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
if (result)
goto liderror;
......
......@@ -3174,7 +3174,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_UNKNOWN,
/* Extra keys in use since the X240 / T440 / T540 */
KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_COMPUTER,
KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_FILE,
},
};
......@@ -6144,7 +6144,7 @@ static int brightness_set(unsigned int value)
{
int res;
if (value > bright_maxlvl || value < 0)
if (value > bright_maxlvl)
return -EINVAL;
vdbg_printk(TPACPI_DBG_BRGHT,
......@@ -6860,7 +6860,7 @@ static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
}
static struct snd_kcontrol_new volume_alsa_control_vol = {
static struct snd_kcontrol_new volume_alsa_control_vol __initdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Console Playback Volume",
.index = 0,
......@@ -6869,7 +6869,7 @@ static struct snd_kcontrol_new volume_alsa_control_vol = {
.get = volume_alsa_vol_get,
};
static struct snd_kcontrol_new volume_alsa_control_mute = {
static struct snd_kcontrol_new volume_alsa_control_mute __initdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Console Playback Switch",
.index = 0,
......
......@@ -222,6 +222,12 @@ static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"),
},
},
{}
};
......@@ -229,6 +235,7 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
{ KE_KEY, 0x157, { KEY_MUTE } },
{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
{ KE_KEY, 0x103, { KEY_ZOOMIN } },
{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
{ KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
......@@ -872,7 +879,9 @@ static int lcd_proc_open(struct inode *inode, struct file *file)
static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
{
u32 hci_result;
u32 in[HCI_WORDS] = { HCI_SET, HCI_LCD_BRIGHTNESS, 0, 0, 0, 0 };
u32 out[HCI_WORDS];
acpi_status status;
if (dev->tr_backlight_supported) {
bool enable = !value;
......@@ -883,9 +892,20 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
value--;
}
value = value << HCI_LCD_BRIGHTNESS_SHIFT;
hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result);
return hci_result == HCI_SUCCESS ? 0 : -EIO;
in[2] = value << HCI_LCD_BRIGHTNESS_SHIFT;
status = hci_raw(dev, in, out);
if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
pr_err("ACPI call to set brightness failed");
return -EIO;
}
/* Extra check for "incomplete" backlight method, where the AML code
* doesn't check for HCI_SET or HCI_GET and returns HCI_SUCCESS,
* the actual brightness, and in some cases the max brightness.
*/
if (out[2] > 0 || out[3] == 0xE000)
return -ENODEV;
return out[0] == HCI_SUCCESS ? 0 : -EIO;
}
static int set_lcd_status(struct backlight_device *bd)
......@@ -1238,7 +1258,7 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
int mode = -1;
int time = -1;
if (sscanf(buf, "%i", &mode) != 1 && (mode != 2 || mode != 1))
if (sscanf(buf, "%i", &mode) != 1 || (mode != 2 || mode != 1))
return -EINVAL;
/* Set the Keyboard Backlight Mode where:
......
/*
* Toshiba HDD Active Protection Sensor (HAPS) driver
*
* Copyright (C) 2014 Azael Avalos <coproscefalo@gmail.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/acpi.h>
MODULE_AUTHOR("Azael Avalos <coproscefalo@gmail.com>");
MODULE_DESCRIPTION("Toshiba HDD Active Protection Sensor");
MODULE_LICENSE("GPL");
struct toshiba_haps_dev {
struct acpi_device *acpi_dev;
int protection_level;
};
static struct toshiba_haps_dev *toshiba_haps;
/* HAPS functions */
static int toshiba_haps_reset_protection(acpi_handle handle)
{
acpi_status status;
status = acpi_evaluate_object(handle, "RSSS", NULL, NULL);
if (ACPI_FAILURE(status)) {
pr_err("Unable to reset the HDD protection\n");
return -EIO;
}
return 0;
}
static int toshiba_haps_protection_level(acpi_handle handle, int level)
{
acpi_status status;
status = acpi_execute_simple_method(handle, "PTLV", level);
if (ACPI_FAILURE(status)) {
pr_err("Error while setting the protection level\n");
return -EIO;
}
pr_info("HDD protection level set to: %d\n", level);
return 0;
}
/* sysfs files */
static ssize_t protection_level_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
return sprintf(buf, "%i\n", haps->protection_level);
}
static ssize_t protection_level_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
int level, ret;
if (sscanf(buf, "%d", &level) != 1 || level < 0 || level > 3)
return -EINVAL;
/* Set the sensor level.
* Acceptable levels are:
* 0 - Disabled | 1 - Low | 2 - Medium | 3 - High
*/
ret = toshiba_haps_protection_level(haps->acpi_dev->handle, level);
if (ret != 0)
return ret;
haps->protection_level = level;
return count;
}
static ssize_t reset_protection_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
int reset, ret;
if (sscanf(buf, "%d", &reset) != 1 || reset != 1)
return -EINVAL;
/* Reset the protection interface */
ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
if (ret != 0)
return ret;
return count;
}
static DEVICE_ATTR(protection_level, S_IRUGO | S_IWUSR,
protection_level_show, protection_level_store);
static DEVICE_ATTR(reset_protection, S_IWUSR, NULL, reset_protection_store);
static struct attribute *haps_attributes[] = {
&dev_attr_protection_level.attr,
&dev_attr_reset_protection.attr,
NULL,
};
static struct attribute_group haps_attr_group = {
.attrs = haps_attributes,
};
/*
* ACPI stuff
*/
static void toshiba_haps_notify(struct acpi_device *device, u32 event)
{
pr_info("Received event: 0x%x", event);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev),
event, 0);
}
static int toshiba_haps_remove(struct acpi_device *device)
{
sysfs_remove_group(&device->dev.kobj, &haps_attr_group);
if (toshiba_haps)
toshiba_haps = NULL;
return 0;
}
/* Helper function */
static int toshiba_haps_available(acpi_handle handle)
{
acpi_status status;
u64 hdd_present;
/*
* A non existent device as well as having (only)
* Solid State Drives can cause the call to fail.
*/
status = acpi_evaluate_integer(handle, "_STA", NULL,
&hdd_present);
if (ACPI_FAILURE(status) || !hdd_present) {
pr_info("HDD protection not available or using SSD\n");
return 0;
}
return 1;
}
static int toshiba_haps_add(struct acpi_device *acpi_dev)
{
struct toshiba_haps_dev *haps;
int ret;
if (toshiba_haps)
return -EBUSY;
if (!toshiba_haps_available(acpi_dev->handle))
return -ENODEV;
pr_info("Toshiba HDD Active Protection Sensor device\n");
haps = kzalloc(sizeof(struct toshiba_haps_dev), GFP_KERNEL);
if (!haps)
return -ENOMEM;
haps->acpi_dev = acpi_dev;
haps->protection_level = 2;
acpi_dev->driver_data = haps;
dev_set_drvdata(&acpi_dev->dev, haps);
/* Set the protection level, currently at level 2 (Medium) */
ret = toshiba_haps_protection_level(acpi_dev->handle, 2);
if (ret != 0)
return ret;
ret = sysfs_create_group(&acpi_dev->dev.kobj, &haps_attr_group);
if (ret)
return ret;
toshiba_haps = haps;
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int toshiba_haps_suspend(struct device *device)
{
struct toshiba_haps_dev *haps;
int ret;
haps = acpi_driver_data(to_acpi_device(device));
/* Deactivate the protection on suspend */
ret = toshiba_haps_protection_level(haps->acpi_dev->handle, 0);
return ret;
}
static int toshiba_haps_resume(struct device *device)
{
struct toshiba_haps_dev *haps;
int ret;
haps = acpi_driver_data(to_acpi_device(device));
/* Set the stored protection level */
ret = toshiba_haps_protection_level(haps->acpi_dev->handle,
haps->protection_level);
/* Reset the protection on resume */
ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
if (ret != 0)
return ret;
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(toshiba_haps_pm,
toshiba_haps_suspend, toshiba_haps_resume);
static const struct acpi_device_id haps_device_ids[] = {
{"TOS620A", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, haps_device_ids);
static struct acpi_driver toshiba_haps_driver = {
.name = "Toshiba HAPS",
.owner = THIS_MODULE,
.ids = haps_device_ids,
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
.ops = {
.add = toshiba_haps_add,
.remove = toshiba_haps_remove,
.notify = toshiba_haps_notify,
},
.drv.pm = &toshiba_haps_pm,
};
module_acpi_driver(toshiba_haps_driver);
......@@ -256,10 +256,6 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
block = &wblock->gblock;
handle = wblock->handle;
if (!block)
return AE_NOT_EXIST;
snprintf(method, 5, "WE%02X", block->notify_id);
status = acpi_execute_simple_method(handle, method, enable);
......
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