* Copyright (C) 2002-2004 John Belmonte
* Copyright (C) 2008 Philip Langdale
* Copyright (C) 2010 Pierre Ducroquet
+ * Copyright (C) 2014 Azael Avalos
*
* 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
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#define TOSHIBA_ACPI_VERSION "0.19"
+#define TOSHIBA_ACPI_VERSION "0.20"
#define PROC_INTERFACE_VERSION 1
#include <linux/kernel.h>
* However the ACPI methods seem to be incomplete in some areas (for
* example they allow setting, but not reading, the LCD brightness value),
* so this is still useful.
- *
+ *
* SCI stands for "System Configuration Interface" which aim is to
* conceal differences in hardware between different models.
*/
#define HCI_FAILURE 0x1000
#define HCI_NOT_SUPPORTED 0x8000
#define HCI_EMPTY 0x8c00
+#define HCI_DATA_NOT_AVAILABLE 0x8d20
+#define HCI_NOT_INITIALIZED 0x8d50
#define SCI_OPEN_CLOSE_OK 0x0044
#define SCI_ALREADY_OPEN 0x8100
#define SCI_NOT_OPENED 0x8200
#define HCI_HOTKEY_EVENT 0x001e
#define HCI_LCD_BRIGHTNESS 0x002a
#define HCI_WIRELESS 0x0056
+#define HCI_ACCELEROMETER 0x006d
#define HCI_KBD_ILLUMINATION 0x0095
#define HCI_ECO_MODE 0x0097
+#define HCI_ACCELEROMETER2 0x00a6
#define SCI_ILLUMINATION 0x014e
#define SCI_KBD_ILLUM_STATUS 0x015c
#define SCI_TOUCHPAD 0x050e
/* field definitions */
+#define HCI_ACCEL_MASK 0x7fff
#define HCI_HOTKEY_DISABLE 0x0b
#define HCI_HOTKEY_ENABLE 0x09
#define HCI_LCD_BRIGHTNESS_BITS 3
unsigned int kbd_led_registered:1;
unsigned int touchpad_supported:1;
unsigned int eco_supported:1;
+ unsigned int accelerometer_supported:1;
unsigned int sysfs_created:1;
struct mutex mutex;
return state ? LED_FULL : LED_OFF;
}
-
+
/* KBD Illumination */
static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
{
return;
}
}
-
+
/* TouchPad support */
static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
{
}
}
+/* Accelerometer support */
+static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
+{
+ u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
+ u32 out[HCI_WORDS];
+ acpi_status status;
+
+ /* Check if the accelerometer call exists,
+ * this call also serves as initialization
+ */
+ status = hci_raw(dev, in, out);
+ if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
+ pr_err("ACPI call to query the accelerometer failed\n");
+ return -EIO;
+ } else if (out[0] == HCI_DATA_NOT_AVAILABLE ||
+ out[0] == HCI_NOT_INITIALIZED) {
+ pr_err("Accelerometer not initialized\n");
+ return -EIO;
+ } else if (out[0] == HCI_NOT_SUPPORTED) {
+ pr_info("Accelerometer not supported\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
+ u32 *xy, u32 *z)
+{
+ u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
+ u32 out[HCI_WORDS];
+ acpi_status status;
+
+ /* Check the Accelerometer status */
+ status = hci_raw(dev, in, out);
+ if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
+ pr_err("ACPI call to query the accelerometer failed\n");
+ return -EIO;
+ }
+
+ *xy = out[2];
+ *z = out[4];
+
+ return 0;
+}
+
/* Bluetooth rfkill handlers */
static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
.get_brightness = get_lcd_brightness,
.update_status = set_lcd_status,
};
-
+
/*
* Sysfs files
*/
return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
}
-
+
static ssize_t toshiba_touchpad_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
return sprintf(buf, "%i\n", state);
}
+static ssize_t toshiba_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 xyval, zval, tmp;
+ u16 x, y, z;
+ int ret;
+
+ xyval = zval = 0;
+ ret = toshiba_accelerometer_get(toshiba, &xyval, &zval);
+ if (ret < 0)
+ return ret;
+
+ x = xyval & HCI_ACCEL_MASK;
+ tmp = xyval >> HCI_MISC_SHIFT;
+ y = tmp & HCI_ACCEL_MASK;
+ z = zval & HCI_ACCEL_MASK;
+
+ return sprintf(buf, "%d %d %d\n", x, y, z);
+}
+
static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
toshiba_touchpad_show, toshiba_touchpad_store);
+static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
static struct attribute *toshiba_attributes[] = {
&dev_attr_kbd_backlight_mode.attr,
&dev_attr_kbd_backlight_timeout.attr,
&dev_attr_touchpad.attr,
+ &dev_attr_position.attr,
NULL,
};
exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
else if (attr == &dev_attr_touchpad.attr)
exists = (drv->touchpad_supported) ? true : false;
+ else if (attr == &dev_attr_position.attr)
+ exists = (drv->accelerometer_supported) ? true : false;
return exists ? attr->mode : 0;
}
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
remove_toshiba_proc_entries(dev);
-
+
if (dev->sysfs_created)
sysfs_remove_group(&dev->acpi_dev->dev.kobj,
&toshiba_attr_group);
if (dev->illumination_supported)
led_classdev_unregister(&dev->led_dev);
-
+
if (dev->kbd_led_registered)
led_classdev_unregister(&dev->kbd_led);
-
+
if (dev->eco_supported)
led_classdev_unregister(&dev->eco_led);
if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
dev->illumination_supported = 1;
}
-
+
if (toshiba_eco_mode_available(dev)) {
dev->eco_led.name = "toshiba::eco_mode";
dev->eco_led.max_brightness = 1;
if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led))
dev->eco_supported = 1;
}
-
+
ret = toshiba_kbd_illum_status_get(dev, &dummy);
if (!ret) {
dev->kbd_time = dummy >> HCI_MISC_SHIFT;
if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
dev->kbd_led_registered = 1;
}
-
+
ret = toshiba_touchpad_get(dev, &dummy);
dev->touchpad_supported = !ret;
+ ret = toshiba_accelerometer_supported(dev);
+ dev->accelerometer_supported = !ret;
+
/* Determine whether or not BIOS supports fan and video interfaces */
ret = get_video_status(dev, &dummy);