Commit 63345b47 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:
 "Nothing overly exciting here - a couple of new drivers that don't do a
  great deal, along with some miscellaneous fixes and a couple of small
  feature enablement patches"

* 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86:
  x86 platform drivers: fix gpio leak
  toshiba_acpi: Add dependency on SERIO_I8042
  asus-nb-wmi: set wapf=4 for ASUSTeK COMPUTER INC. 1015E/U
  Add trivial driver to disable Intel Smart Connect
  Add support driver for Intel Rapid Start Technology
  hp-wmi: add supports for POST code error
  asus-wmi: control wlan-led only if wapf == 4
  drivers/platform/x86/intel_ips: Convert to module_pci_driver
  asus-nb-wmi: ignore ALS notification key code
  asus-wmi: append newline to messages
  x86: asus-laptop: fix invalid point access
  x86: msi-laptop: fix memleak
  amilo-rfkill: Add dependency on SERIO_I8042
  dell-laptop: fix error return code in dell_init()
  hp-wmi: Enable hotkeys on some systems
parents 18fb38e2 fef8ce16
What: /sys/bus/acpi/intel-rapid-start/wakeup_events
Date: July 2, 2013
KernelVersion: 3.11
Contact: Matthew Garrett <mjg59@srcf.ucam.org>
Description: An integer representing a set of wakeup events as follows:
1: Wake to enter hibernation when the wakeup timer expires
2: Wake to enter hibernation when the battery reaches a
critical level
These values are ORed together. For example, a value of 3
indicates that the system will wake to enter hibernation when
either the wakeup timer expires or the battery reaches a
critical level.
What: /sys/bus/acpi/intel-rapid-start/wakeup_time
Date: July 2, 2013
KernelVersion: 3.11
Contact: Matthew Garrett <mjg59@srcf.ucam.org>
Description: An integer representing the length of time the system will
remain asleep before waking up to enter hibernation.
This value is in minutes.
......@@ -176,6 +176,7 @@ config FUJITSU_TABLET
config AMILO_RFKILL
tristate "Fujitsu-Siemens Amilo rfkill support"
depends on RFKILL
depends on SERIO_I8042
---help---
This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
laptops.
......@@ -591,6 +592,7 @@ config ACPI_TOSHIBA
depends on BACKLIGHT_CLASS_DEVICE
depends on INPUT
depends on RFKILL || RFKILL = n
depends on SERIO_I8042 || SERIO_I8042 = n
select INPUT_POLLDEV
select INPUT_SPARSEKMAP
---help---
......@@ -781,6 +783,32 @@ config APPLE_GMUX
graphics as well as the backlight. Currently only backlight
control is supported by the driver.
config INTEL_RST
tristate "Intel Rapid Start Technology Driver"
depends on ACPI
---help---
This driver provides support for modifying paramaters on systems
equipped with Intel's Rapid Start Technology. When put in an ACPI
sleep state, these devices will wake after either a configured
timeout or when the system battery reaches a critical state,
automatically copying memory contents to disk. On resume, the
firmware will copy the memory contents back to RAM and resume the OS
as usual.
config INTEL_SMARTCONNECT
tristate "Intel Smart Connect disabling driver"
depends on ACPI
---help---
Intel Smart Connect is a technology intended to permit devices to
update state by resuming for a short period of time at regular
intervals. If a user enables this functionality under Windows and
then reboots into Linux, the system may remain configured to resume
on suspend. In the absence of any userspace to support it, the system
will then remain awake until something triggers another suspend.
This driver checks to determine whether the device has Intel Smart
Connect enabled, and if so disables it.
config PVPANIC
tristate "pvpanic device support"
depends on ACPI
......
......@@ -51,5 +51,7 @@ obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
obj-$(CONFIG_INTEL_RST) += intel-rst.o
obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
......@@ -1935,7 +1935,6 @@ fail_input:
fail_backlight:
asus_platform_exit(asus);
fail_platform:
kfree(asus->name);
kfree(asus);
return result;
......
......@@ -180,6 +180,24 @@ static struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_x401u,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. 1015E",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1015E"),
},
.driver_data = &quirk_asus_x401u,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. 1015U",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1015U"),
},
.driver_data = &quirk_asus_x401u,
},
{},
};
......@@ -256,6 +274,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0xB5, { KEY_CALC } },
{ KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
{ KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
{ KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */
{ KE_END, 0},
};
......
......@@ -558,7 +558,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
goto error;
}
if (wlan_led_presence(asus)) {
if (wlan_led_presence(asus) && (asus->driver->quirks->wapf == 4)) {
INIT_WORK(&asus->wlan_led_work, wlan_led_update);
asus->wlan_led.name = "asus::wlan";
......@@ -886,7 +886,8 @@ static int asus_new_rfkill(struct asus_wmi *asus,
if (!*rfkill)
return -EINVAL;
if (dev_id == ASUS_WMI_DEVID_WLAN)
if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
(asus->driver->quirks->wapf == 4))
rfkill_set_led_trigger_name(*rfkill, "asus-wlan");
rfkill_init_sw_state(*rfkill, !result);
......@@ -1045,7 +1046,7 @@ static ssize_t asus_hwmon_pwm1(struct device *dev,
else if (value == 3)
value = 255;
else if (value != 0) {
pr_err("Unknown fan speed %#x", value);
pr_err("Unknown fan speed %#x\n", value);
value = -1;
}
......@@ -1557,11 +1558,11 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
/* INIT enable hotkeys on some models */
if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv))
pr_info("Initialization: %#x", rv);
pr_info("Initialization: %#x\n", rv);
/* We don't know yet what to do with this version... */
if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) {
pr_info("BIOS WMI version: %d.%d", rv >> 16, rv & 0xFF);
pr_info("BIOS WMI version: %d.%d\n", rv >> 16, rv & 0xFF);
asus->spec = rv;
}
......@@ -1572,7 +1573,7 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
* The significance of others is yet to be found.
*/
if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) {
pr_info("SFUN value: %#x", rv);
pr_info("SFUN value: %#x\n", rv);
asus->sfun = rv;
}
......@@ -1712,7 +1713,7 @@ static int asus_wmi_debugfs_init(struct asus_wmi *asus)
asus->debug.root = debugfs_create_dir(asus->driver->name, NULL);
if (!asus->debug.root) {
pr_err("failed to create debugfs directory");
pr_err("failed to create debugfs directory\n");
goto error_debugfs;
}
......@@ -1985,17 +1986,17 @@ EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver);
static int __init asus_wmi_init(void)
{
if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
pr_info("Asus Management GUID not found");
pr_info("Asus Management GUID not found\n");
return -ENODEV;
}
pr_info("ASUS WMI generic driver loaded");
pr_info("ASUS WMI generic driver loaded\n");
return 0;
}
static void __exit asus_wmi_exit(void)
{
pr_info("ASUS WMI generic driver unloaded");
pr_info("ASUS WMI generic driver unloaded\n");
}
module_init(asus_wmi_init);
......
......@@ -551,9 +551,10 @@ static int __init dell_init(void)
* is passed to SMI handler.
*/
bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32);
if (!bufferpage)
if (!bufferpage) {
ret = -ENOMEM;
goto fail_buffer;
}
buffer = page_address(bufferpage);
if (quirks && quirks->touchpad_led)
......
......@@ -53,8 +53,10 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
#define HPWMI_ALS_QUERY 0x3
#define HPWMI_HARDWARE_QUERY 0x4
#define HPWMI_WIRELESS_QUERY 0x5
#define HPWMI_BIOS_QUERY 0x9
#define HPWMI_HOTKEY_QUERY 0xc
#define HPWMI_WIRELESS2_QUERY 0x1b
#define HPWMI_POSTCODEERROR_QUERY 0x2a
enum hp_wmi_radio {
HPWMI_WIFI = 0,
......@@ -291,6 +293,19 @@ static int hp_wmi_tablet_state(void)
return (state & 0x4) ? 1 : 0;
}
static int hp_wmi_enable_hotkeys(void)
{
int ret;
int query = 0x6e;
ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query),
0);
if (ret)
return -EINVAL;
return 0;
}
static int hp_wmi_set_block(void *data, bool blocked)
{
enum hp_wmi_radio r = (enum hp_wmi_radio) data;
......@@ -386,6 +401,16 @@ static int hp_wmi_rfkill2_refresh(void)
return 0;
}
static int hp_wmi_post_code_state(void)
{
int state = 0;
int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 0, &state,
sizeof(state), sizeof(state));
if (ret)
return -EINVAL;
return state;
}
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
char *buf)
{
......@@ -431,6 +456,16 @@ static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", value);
}
static ssize_t show_postcode(struct device *dev, struct device_attribute *attr,
char *buf)
{
/* Get the POST error code of previous boot failure. */
int value = hp_wmi_post_code_state();
if (value < 0)
return -EINVAL;
return sprintf(buf, "0x%x\n", value);
}
static ssize_t set_als(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
......@@ -443,11 +478,33 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
return count;
}
static ssize_t set_postcode(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
u32 tmp;
long unsigned int tmp2;
ret = kstrtoul(buf, 10, &tmp2);
if (ret || tmp2 != 1)
return -EINVAL;
/* Clear the POST error code. It is kept until until cleared. */
tmp = (u32) tmp2;
ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 1, &tmp,
sizeof(tmp), sizeof(tmp));
if (ret)
return -EINVAL;
return count;
}
static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
static DEVICE_ATTR(postcode, S_IRUGO | S_IWUSR, show_postcode, set_postcode);
static void hp_wmi_notify(u32 value, void *context)
{
......@@ -628,6 +685,7 @@ static void cleanup_sysfs(struct platform_device *device)
device_remove_file(&device->dev, &dev_attr_als);
device_remove_file(&device->dev, &dev_attr_dock);
device_remove_file(&device->dev, &dev_attr_tablet);
device_remove_file(&device->dev, &dev_attr_postcode);
}
static int hp_wmi_rfkill_setup(struct platform_device *device)
......@@ -843,6 +901,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
if (err)
goto add_sysfs_error;
err = device_create_file(&device->dev, &dev_attr_tablet);
if (err)
goto add_sysfs_error;
err = device_create_file(&device->dev, &dev_attr_postcode);
if (err)
goto add_sysfs_error;
return 0;
......@@ -948,6 +1009,8 @@ static int __init hp_wmi_init(void)
err = hp_wmi_input_setup();
if (err)
return err;
hp_wmi_enable_hotkeys();
}
if (bios_capable) {
......
/*
* Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org>
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <acpi/acpi_drivers.h>
MODULE_LICENSE("GPL");
static ssize_t irst_show_wakeup_events(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct acpi_device *acpi;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *result;
acpi_status status;
acpi = to_acpi_device(dev);
status = acpi_evaluate_object(acpi->handle, "GFFS", NULL, &output);
if (!ACPI_SUCCESS(status))
return -EINVAL;
result = output.pointer;
if (result->type != ACPI_TYPE_INTEGER) {
kfree(result);
return -EINVAL;
}
return sprintf(buf, "%lld\n", result->integer.value);
}
static ssize_t irst_store_wakeup_events(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct acpi_device *acpi;
struct acpi_object_list input;
union acpi_object param;
acpi_status status;
unsigned long value;
int error;
acpi = to_acpi_device(dev);
error = kstrtoul(buf, 0, &value);
if (error)
return error;
param.type = ACPI_TYPE_INTEGER;
param.integer.value = value;
input.count = 1;
input.pointer = &param;
status = acpi_evaluate_object(acpi->handle, "SFFS", &input, NULL);
if (!ACPI_SUCCESS(status))
return -EINVAL;
return count;
}
static struct device_attribute irst_wakeup_attr = {
.attr = { .name = "wakeup_events", .mode = 0600 },
.show = irst_show_wakeup_events,
.store = irst_store_wakeup_events
};
static ssize_t irst_show_wakeup_time(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct acpi_device *acpi;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *result;
acpi_status status;
acpi = to_acpi_device(dev);
status = acpi_evaluate_object(acpi->handle, "GFTV", NULL, &output);
if (!ACPI_SUCCESS(status))
return -EINVAL;
result = output.pointer;
if (result->type != ACPI_TYPE_INTEGER) {
kfree(result);
return -EINVAL;
}
return sprintf(buf, "%lld\n", result->integer.value);
}
static ssize_t irst_store_wakeup_time(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct acpi_device *acpi;
struct acpi_object_list input;
union acpi_object param;
acpi_status status;
unsigned long value;
int error;
acpi = to_acpi_device(dev);
error = kstrtoul(buf, 0, &value);
if (error)
return error;
param.type = ACPI_TYPE_INTEGER;
param.integer.value = value;
input.count = 1;
input.pointer = &param;
status = acpi_evaluate_object(acpi->handle, "SFTV", &input, NULL);
if (!ACPI_SUCCESS(status))
return -EINVAL;
return count;
}
static struct device_attribute irst_timeout_attr = {
.attr = { .name = "wakeup_time", .mode = 0600 },
.show = irst_show_wakeup_time,
.store = irst_store_wakeup_time
};
static int irst_add(struct acpi_device *acpi)
{
int error = 0;
error = device_create_file(&acpi->dev, &irst_timeout_attr);
if (error)
goto out;
error = device_create_file(&acpi->dev, &irst_wakeup_attr);
if (error)
goto out_timeout;
return 0;
out_timeout:
device_remove_file(&acpi->dev, &irst_timeout_attr);
out:
return error;
}
static int irst_remove(struct acpi_device *acpi)
{
device_remove_file(&acpi->dev, &irst_wakeup_attr);
device_remove_file(&acpi->dev, &irst_timeout_attr);
return 0;
}
static const struct acpi_device_id irst_ids[] = {
{"INT3392", 0},
{"", 0}
};
static struct acpi_driver irst_driver = {
.owner = THIS_MODULE,
.name = "intel_rapid_start",
.class = "intel_rapid_start",
.ids = irst_ids,
.ops = {
.add = irst_add,
.remove = irst_remove,
},
};
static int irst_init(void)
{
return acpi_bus_register_driver(&irst_driver);
}
static void irst_exit(void)
{
acpi_bus_unregister_driver(&irst_driver);
}
module_init(irst_init);
module_exit(irst_exit);
MODULE_DEVICE_TABLE(acpi, irst_ids);
/*
* Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org>
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <acpi/acpi_drivers.h>
MODULE_LICENSE("GPL");
static int smartconnect_acpi_init(struct acpi_device *acpi)
{
struct acpi_object_list input;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *result;
union acpi_object param;
acpi_status status;
status = acpi_evaluate_object(acpi->handle, "GAOS", NULL, &output);
if (!ACPI_SUCCESS(status))
return -EINVAL;
result = output.pointer;
if (result->type != ACPI_TYPE_INTEGER) {
kfree(result);
return -EINVAL;
}
if (result->integer.value & 0x1) {
param.type = ACPI_TYPE_INTEGER;
param.integer.value = 0;
input.count = 1;
input.pointer = &param;
dev_info(&acpi->dev, "Disabling Intel Smart Connect\n");
status = acpi_evaluate_object(acpi->handle, "SAOS", &input,
NULL);
}
kfree(result);
return 0;
}
static const struct acpi_device_id smartconnect_ids[] = {
{"INT33A0", 0},
{"", 0}
};
static struct acpi_driver smartconnect_driver = {
.owner = THIS_MODULE,
.name = "intel_smart_connect",
.class = "intel_smart_connect",
.ids = smartconnect_ids,
.ops = {
.add = smartconnect_acpi_init,