diff options
author | Pierre Ducroquet <pinaraf@pinaraf.info> | 2010-07-29 11:56:59 +0200 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2010-08-03 09:49:10 -0400 |
commit | 6c3f6e6c575a0a992429427d4978c6091756a526 (patch) | |
tree | 596239acbe95dcd6b936683ca515c9b97a01a75b /drivers/platform | |
parent | 5ca56718917a353a7a916b182f6d7f1f2479c5bf (diff) | |
download | op-kernel-dev-6c3f6e6c575a0a992429427d4978c6091756a526.zip op-kernel-dev-6c3f6e6c575a0a992429427d4978c6091756a526.tar.gz |
toshiba-acpi: Add support for Toshiba Illumination.
Add support for Toshiba Illumination. This is a set of LEDs installed on
some Toshiba laptops. It is controlled through ACPI, the commands has been
found through reverse engineering. It has been tested on a Toshiba Qosmio
G50-122.
Signed-off-by: Pierre Ducroquet <pinaraf@pinaraf.info>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 627fc38..7d67a45 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -4,6 +4,7 @@ * * Copyright (C) 2002-2004 John Belmonte * Copyright (C) 2008 Philip Langdale + * Copyright (C) 2010 Pierre Ducroquet * * 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 @@ -47,6 +48,7 @@ #include <linux/platform_device.h> #include <linux/rfkill.h> #include <linux/input.h> +#include <linux/leds.h> #include <linux/slab.h> #include <asm/uaccess.h> @@ -287,6 +289,7 @@ struct toshiba_acpi_dev { struct platform_device *p_dev; struct rfkill *bt_rfk; struct input_dev *hotkey_dev; + int illumination_installed; acpi_handle handle; const char *bt_name; @@ -294,6 +297,110 @@ struct toshiba_acpi_dev { struct mutex mutex; }; +/* Illumination support */ +static int toshiba_illumination_available(void) +{ + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; + u32 out[HCI_WORDS]; + acpi_status status; + + in[0] = 0xf100; + status = hci_raw(in, out); + if (ACPI_FAILURE(status)) { + printk(MY_INFO "Illumination device not available\n"); + return 0; + } + in[0] = 0xf400; + status = hci_raw(in, out); + return 1; +} + +static void toshiba_illumination_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; + u32 out[HCI_WORDS]; + acpi_status status; + + /* First request : initialize communication. */ + in[0] = 0xf100; + status = hci_raw(in, out); + if (ACPI_FAILURE(status)) { + printk(MY_INFO "Illumination device not available\n"); + return; + } + + if (brightness) { + /* Switch the illumination on */ + in[0] = 0xf400; + in[1] = 0x14e; + in[2] = 1; + status = hci_raw(in, out); + if (ACPI_FAILURE(status)) { + printk(MY_INFO "ACPI call for illumination failed.\n"); + return; + } + } else { + /* Switch the illumination off */ + in[0] = 0xf400; + in[1] = 0x14e; + in[2] = 0; + status = hci_raw(in, out); + if (ACPI_FAILURE(status)) { + printk(MY_INFO "ACPI call for illumination failed.\n"); + return; + } + } + + /* Last request : close communication. */ + in[0] = 0xf200; + in[1] = 0; + in[2] = 0; + hci_raw(in, out); +} + +static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) +{ + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; + u32 out[HCI_WORDS]; + acpi_status status; + enum led_brightness result; + + /* First request : initialize communication. */ + in[0] = 0xf100; + status = hci_raw(in, out); + if (ACPI_FAILURE(status)) { + printk(MY_INFO "Illumination device not available\n"); + return LED_OFF; + } + + /* Check the illumination */ + in[0] = 0xf300; + in[1] = 0x14e; + status = hci_raw(in, out); + if (ACPI_FAILURE(status)) { + printk(MY_INFO "ACPI call for illumination failed.\n"); + return LED_OFF; + } + + result = out[2] ? LED_FULL : LED_OFF; + + /* Last request : close communication. */ + in[0] = 0xf200; + in[1] = 0; + in[2] = 0; + hci_raw(in, out); + + return result; +} + +static struct led_classdev toshiba_led = { + .name = "toshiba::illumination", + .max_brightness = 1, + .brightness_set = toshiba_illumination_set, + .brightness_get = toshiba_illumination_get, +}; + static struct toshiba_acpi_dev toshiba_acpi = { .bt_name = "Toshiba Bluetooth", }; @@ -913,6 +1020,9 @@ static void toshiba_acpi_exit(void) acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY, toshiba_acpi_notify); + if (toshiba_acpi.illumination_installed) + led_classdev_unregister(&toshiba_led); + platform_device_unregister(toshiba_acpi.p_dev); return; @@ -1007,6 +1117,13 @@ static int __init toshiba_acpi_init(void) } } + toshiba_acpi.illumination_installed = 0; + if (toshiba_illumination_available()) { + if (!led_classdev_register(&(toshiba_acpi.p_dev->dev), + &toshiba_led)) + toshiba_acpi.illumination_installed = 1; + } + return 0; } |