diff -Npur linux-3.8.10/drivers/platform/x86/Kconfig linux-3.8.10-new/drivers/platform/x86/Kconfig --- linux-3.8.10/drivers/platform/x86/Kconfig 2013-04-26 15:18:32.000000000 -0400 +++ linux-3.8.10-new/drivers/platform/x86/Kconfig 2013-04-29 20:16:26.100007750 -0400 @@ -620,6 +620,22 @@ 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_HDAPS + tristate "Toshiba HDAPS support" + depends on ACPI + ---help--- + This driver adds support for Toshiba HDAPS accelerometer events on + modern Toshiba laptops equipped with an HDAPS device. + + This driver receives a standard ACPI event when the HDAPS device + detects any movement or vibration of the laptop, and another + event shortly after detected vibration has stopped. A userspace daemon + is needed to park / unpark heads. Use 'protlevel={1,2,3}' to set + sensitivity level. Default is 2. + + If you have a modern Toshiba laptop with an HDAPS TOS620A device, + say Y. + config ACPI_CMPC tristate "CMPC Laptop Extras" depends on X86 && ACPI diff -Npur linux-3.8.10/drivers/platform/x86/Makefile linux-3.8.10-new/drivers/platform/x86/Makefile --- linux-3.8.10/drivers/platform/x86/Makefile 2013-04-26 15:18:32.000000000 -0400 +++ linux-3.8.10-new/drivers/platform/x86/Makefile 2013-04-29 20:16:19.677008053 -0400 @@ -36,6 +36,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar- obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o +obj-$(CONFIG_TOSHIBA_HDAPS) += toshiba_hdaps.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 diff -Npur linux-3.8.10/drivers/platform/x86/toshiba_hdaps.c linux-3.8.10-new/drivers/platform/x86/toshiba_hdaps.c --- linux-3.8.10/drivers/platform/x86/toshiba_hdaps.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-3.8.10-new/drivers/platform/x86/toshiba_hdaps.c 2013-04-29 20:16:31.330007503 -0400 @@ -0,0 +1,266 @@ +/* + * toshiba_hdaps.c - Toshiba ACPI HDAPS Accelerometer Driver + * + * + * Copyright (C) 2013 Nathaniel M Nelson + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +ACPI_MODULE_NAME("toshiba_hdaps"); +MODULE_AUTHOR("Nathaniel M Nelson"); +MODULE_DESCRIPTION("Toshiba ACPI HDAPS Accelerometer Driver"); +MODULE_LICENSE("GPL"); + +#define ACPI_HDAPS_PROTLEVEL_OFF 0x00 +#define ACPI_HDAPS_PROTLEVEL_LVL1 0x01 +#define ACPI_HDAPS_PROTLEVEL_LVL2 0x02 +#define ACPI_HDAPS_PROTLEVEL_LVL3 0x03 + +static int protlevel = 2; +module_param(protlevel, int, S_IRUGO); + +static int toshiba_hdaps_device_add(struct acpi_device *device); +static int toshiba_hdaps_device_remove(struct acpi_device *device, int type); +static void toshiba_hdaps_device_notify(struct acpi_device *device, u32 event); +static ssize_t toshiba_hdaps_device_status_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t toshiba_hdaps_device_protlevel_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t toshiba_hdaps_device_protlevel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static acpi_status toshiba_hdaps_device_set_protectionlevel(acpi_handle handle, + int prot_level); +static void toshiba_hdaps_device_remove_attrs(struct device *dev); +static int toshiba_hdaps_device_create_attrs(struct device *dev); + +#ifdef CONFIG_PM_SLEEP +static int toshiba_hdaps_device_resume(struct device *device); +#endif + +static SIMPLE_DEV_PM_OPS(toshiba_hdaps_pm, NULL, + toshiba_hdaps_device_resume); +static const struct acpi_device_id hdaps_device_ids[] = { + { "TOS620A", 0}, + { "", 0} +}; +MODULE_DEVICE_TABLE(acpi, hdaps_device_ids); + +static DEVICE_ATTR(status, 0444, toshiba_hdaps_device_status_show, NULL); +static DEVICE_ATTR(protlevel, 0644, toshiba_hdaps_device_protlevel_show, + toshiba_hdaps_device_protlevel_store); + +static struct acpi_driver toshiba_hdaps_device_driver = +{ + .name = "toshiba_hdaps", + .class = "misc", + .ids = hdaps_device_ids, + .ops = { + .add = toshiba_hdaps_device_add, + .remove = toshiba_hdaps_device_remove, + .notify = toshiba_hdaps_device_notify, + }, + .drv.pm = &toshiba_hdaps_pm, + .owner = THIS_MODULE, +}; + +static ssize_t toshiba_hdaps_device_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u64 hdaps_present; + acpi_status status; + struct acpi_device *acpi_dev = to_acpi_device(dev); + + int result; + status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &hdaps_present); + + if (ACPI_FAILURE(status) || !hdaps_present) + result = -ENODEV; + else + result = 1; + + return sprintf(buf, "%i\n", result); +} + +static ssize_t toshiba_hdaps_device_protlevel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%i\n", protlevel); +} + +static ssize_t toshiba_hdaps_device_protlevel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int newprotlevel; + acpi_status status; + struct acpi_device *acpi_dev = to_acpi_device(dev); + + if (sscanf(buf, "%i", &newprotlevel) != 1 || + newprotlevel < 1 || newprotlevel > 3) + return -EINVAL; + + status = toshiba_hdaps_device_set_protectionlevel(acpi_dev->handle, newprotlevel); + + if (ACPI_FAILURE(status)) + return -EINVAL; + + protlevel = newprotlevel; + + pr_info("TOS620A HDAPS device protection level set to %i\n", + newprotlevel); + + return count; +} + +static acpi_status toshiba_hdaps_device_set_protectionlevel(acpi_handle handle, + int prot_level) +{ + struct acpi_object_list params; + union acpi_object in_objs[1]; + acpi_status status; + + params.count = ARRAY_SIZE(in_objs); + params.pointer = in_objs; + in_objs[0].type = ACPI_TYPE_INTEGER; + in_objs[0].integer.value = prot_level; + + status = acpi_evaluate_object(handle, "PTLV", ¶ms, NULL); + return (status == AE_OK) ? 0 : -EIO; +} + +static void toshiba_hdaps_device_notify(struct acpi_device *device, u32 event) +{ + + acpi_bus_generate_proc_event(device, (u8)event, 0); + + acpi_bus_generate_netlink_event(device->pnp.device_class + ,dev_name(&device->dev), event, 0); +} + + +static int toshiba_hdaps_device_enable(acpi_handle handle) +{ + acpi_status status; + u64 hdaps_present; + + /* Check if device actually exists */ + status = acpi_evaluate_integer(handle, "_STA", NULL, &hdaps_present); + + if (ACPI_FAILURE(status) || !hdaps_present) + return -ENODEV; + + status = toshiba_hdaps_device_set_protectionlevel(handle, + protlevel); + + if (ACPI_FAILURE(status)) + return -EINVAL; + + pr_info("TOS620A HDAPS device registered with protection level %i\n", + protlevel); + return 0; + +} + +static int toshiba_hdaps_device_create_attrs(struct device *dev) +{ + int result; + + result = device_create_file(dev, &dev_attr_protlevel); + if (result) + { + toshiba_hdaps_device_remove_attrs(dev); + return -EINVAL; + } + + result = device_create_file(dev, &dev_attr_status); + if (result) + { + toshiba_hdaps_device_remove_attrs(dev); + return -EINVAL; + } + + return 0; +} + + +static int toshiba_hdaps_device_add(struct acpi_device *device) +{ + int result; + result = toshiba_hdaps_device_enable(device->handle); + if (!result) + { + result = toshiba_hdaps_device_create_attrs(&device->dev); + } + + return result; +} + +static int __init toshiba_hdaps_device_init(void) +{ + int result = 0; + + if (protlevel < 1 || protlevel > 3) + return -EINVAL; + + result = acpi_bus_register_driver(&toshiba_hdaps_device_driver); + + if (result < 0) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error registering driver\n")); + return -ENODEV; + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int toshiba_hdaps_device_resume(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + return toshiba_hdaps_device_enable(acpi_dev->handle); +} + +#endif + +static void toshiba_hdaps_device_remove_attrs(struct device *dev) +{ + device_remove_file(dev, &dev_attr_protlevel); + device_remove_file(dev, &dev_attr_status); +} + +static int toshiba_hdaps_device_remove(struct acpi_device *device, int type) +{ + toshiba_hdaps_device_set_protectionlevel(device, + ACPI_HDAPS_PROTLEVEL_OFF); + toshiba_hdaps_device_remove_attrs(&device->dev); + pr_info("TOS620A HDAPS device removed\n"); + return 0; +} + +static void __exit toshiba_hdaps_device_exit(void) +{ + acpi_bus_unregister_driver(&toshiba_hdaps_device_driver); +} + +module_init(toshiba_hdaps_device_init); +module_exit(toshiba_hdaps_device_exit);