diff options
author | Azael Avalos <coproscefalo@gmail.com> | 2014-03-25 22:38:32 -0400 |
---|---|---|
committer | Matthew Garrett <matthew.garrett@nebula.com> | 2014-04-06 12:58:14 -0400 |
commit | 9d8658acd6be9139ef91dfe6c001796e7a03ded6 (patch) | |
tree | 6168958b990e05c8100f579c97ef6af23d65f875 /drivers/platform | |
parent | 360f0f39d0c58432574655008ec8dd15e52e1e8d (diff) |
toshiba_acpi: Add touchpad enable/disable support-
Toshiba laptops have two ways of letting userspace
know the touchpad has changed state, one with a
button on top of the touchpad that simply emmits
scancodes whenever enabled/disabled, and another one
by pressing Fn-F9 (touchpad toggle) hotkey.
This patch adds support to enable/disable the touchpad
by exposing the _touchpad_ file in sysfs that simply
makes a call to a SCI register, imitating what
Toshiba provided software does on Windows.
Signed-off-by: Azael Avalos <coproscefalo@gmail.com>
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 95ae1ffaf409..08c53768447b 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
@@ -114,6 +114,7 @@ MODULE_LICENSE("GPL"); | |||
114 | #define HCI_KBD_ILLUMINATION 0x0095 | 114 | #define HCI_KBD_ILLUMINATION 0x0095 |
115 | #define SCI_ILLUMINATION 0x014e | 115 | #define SCI_ILLUMINATION 0x014e |
116 | #define SCI_KBD_ILLUM_STATUS 0x015c | 116 | #define SCI_KBD_ILLUM_STATUS 0x015c |
117 | #define SCI_TOUCHPAD 0x050e | ||
117 | 118 | ||
118 | /* field definitions */ | 119 | /* field definitions */ |
119 | #define HCI_HOTKEY_DISABLE 0x0b | 120 | #define HCI_HOTKEY_DISABLE 0x0b |
@@ -157,6 +158,7 @@ struct toshiba_acpi_dev { | |||
157 | unsigned int tr_backlight_supported:1; | 158 | unsigned int tr_backlight_supported:1; |
158 | unsigned int kbd_illum_supported:1; | 159 | unsigned int kbd_illum_supported:1; |
159 | unsigned int kbd_led_registered:1; | 160 | unsigned int kbd_led_registered:1; |
161 | unsigned int touchpad_supported:1; | ||
160 | unsigned int sysfs_created:1; | 162 | unsigned int sysfs_created:1; |
161 | 163 | ||
162 | struct mutex mutex; | 164 | struct mutex mutex; |
@@ -527,6 +529,47 @@ static void toshiba_kbd_backlight_set(struct led_classdev *cdev, | |||
527 | return; | 529 | return; |
528 | } | 530 | } |
529 | } | 531 | } |
532 | |||
533 | /* TouchPad support */ | ||
534 | static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) | ||
535 | { | ||
536 | u32 result; | ||
537 | acpi_status status; | ||
538 | |||
539 | if (!sci_open(dev)) | ||
540 | return -EIO; | ||
541 | |||
542 | status = sci_write(dev, SCI_TOUCHPAD, state, &result); | ||
543 | sci_close(dev); | ||
544 | if (ACPI_FAILURE(status)) { | ||
545 | pr_err("ACPI call to set the touchpad failed\n"); | ||
546 | return -EIO; | ||
547 | } else if (result == HCI_NOT_SUPPORTED) { | ||
548 | return -ENODEV; | ||
549 | } | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) | ||
555 | { | ||
556 | u32 result; | ||
557 | acpi_status status; | ||
558 | |||
559 | if (!sci_open(dev)) | ||
560 | return -EIO; | ||
561 | |||
562 | status = sci_read(dev, SCI_TOUCHPAD, state, &result); | ||
563 | sci_close(dev); | ||
564 | if (ACPI_FAILURE(status)) { | ||
565 | pr_err("ACPI call to query the touchpad failed\n"); | ||
566 | return -EIO; | ||
567 | } else if (result == HCI_NOT_SUPPORTED) { | ||
568 | return -ENODEV; | ||
569 | } | ||
570 | |||
571 | return 0; | ||
572 | } | ||
530 | 573 | ||
531 | /* Bluetooth rfkill handlers */ | 574 | /* Bluetooth rfkill handlers */ |
532 | 575 | ||
@@ -1130,15 +1173,48 @@ static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev, | |||
1130 | 1173 | ||
1131 | return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); | 1174 | return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); |
1132 | } | 1175 | } |
1176 | |||
1177 | static ssize_t toshiba_touchpad_store(struct device *dev, | ||
1178 | struct device_attribute *attr, | ||
1179 | const char *buf, size_t count) | ||
1180 | { | ||
1181 | struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); | ||
1182 | int state; | ||
1183 | |||
1184 | /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ | ||
1185 | if (sscanf(buf, "%i", &state) == 1 && (state == 0 || state == 1)) { | ||
1186 | if (toshiba_touchpad_set(toshiba, state) < 0) | ||
1187 | return -EIO; | ||
1188 | } | ||
1189 | |||
1190 | return count; | ||
1191 | } | ||
1192 | |||
1193 | static ssize_t toshiba_touchpad_show(struct device *dev, | ||
1194 | struct device_attribute *attr, char *buf) | ||
1195 | { | ||
1196 | struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); | ||
1197 | u32 state; | ||
1198 | int ret; | ||
1199 | |||
1200 | ret = toshiba_touchpad_get(toshiba, &state); | ||
1201 | if (ret < 0) | ||
1202 | return ret; | ||
1203 | |||
1204 | return sprintf(buf, "%i\n", state); | ||
1205 | } | ||
1133 | 1206 | ||
1134 | static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR, | 1207 | static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR, |
1135 | toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store); | 1208 | toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store); |
1136 | static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR, | 1209 | static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR, |
1137 | toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store); | 1210 | toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store); |
1211 | static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR, | ||
1212 | toshiba_touchpad_show, toshiba_touchpad_store); | ||
1138 | 1213 | ||
1139 | static struct attribute *toshiba_attributes[] = { | 1214 | static struct attribute *toshiba_attributes[] = { |
1140 | &dev_attr_kbd_backlight_mode.attr, | 1215 | &dev_attr_kbd_backlight_mode.attr, |
1141 | &dev_attr_kbd_backlight_timeout.attr, | 1216 | &dev_attr_kbd_backlight_timeout.attr, |
1217 | &dev_attr_touchpad.attr, | ||
1142 | NULL, | 1218 | NULL, |
1143 | }; | 1219 | }; |
1144 | 1220 | ||
@@ -1153,6 +1229,8 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, | |||
1153 | exists = (drv->kbd_illum_supported) ? true : false; | 1229 | exists = (drv->kbd_illum_supported) ? true : false; |
1154 | else if (attr == &dev_attr_kbd_backlight_timeout.attr) | 1230 | else if (attr == &dev_attr_kbd_backlight_timeout.attr) |
1155 | exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; | 1231 | exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; |
1232 | else if (attr == &dev_attr_touchpad.attr) | ||
1233 | exists = (drv->touchpad_supported) ? true : false; | ||
1156 | 1234 | ||
1157 | return exists ? attr->mode : 0; | 1235 | return exists ? attr->mode : 0; |
1158 | } | 1236 | } |
@@ -1496,6 +1574,9 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
1496 | if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) | 1574 | if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) |
1497 | dev->kbd_led_registered = 1; | 1575 | dev->kbd_led_registered = 1; |
1498 | } | 1576 | } |
1577 | |||
1578 | ret = toshiba_touchpad_get(dev, &dummy); | ||
1579 | dev->touchpad_supported = !ret; | ||
1499 | 1580 | ||
1500 | /* Determine whether or not BIOS supports fan and video interfaces */ | 1581 | /* Determine whether or not BIOS supports fan and video interfaces */ |
1501 | 1582 | ||