Commit 6c3f6e6c authored by Pierre Ducroquet's avatar Pierre Ducroquet Committed by Matthew Garrett

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: default avatarPierre Ducroquet <pinaraf@pinaraf.info>
Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
parent 5ca56718
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* *
* Copyright (C) 2002-2004 John Belmonte * Copyright (C) 2002-2004 John Belmonte
* Copyright (C) 2008 Philip Langdale * Copyright (C) 2008 Philip Langdale
* Copyright (C) 2010 Pierre Ducroquet
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -47,6 +48,7 @@ ...@@ -47,6 +48,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rfkill.h> #include <linux/rfkill.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/leds.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -287,6 +289,7 @@ struct toshiba_acpi_dev { ...@@ -287,6 +289,7 @@ struct toshiba_acpi_dev {
struct platform_device *p_dev; struct platform_device *p_dev;
struct rfkill *bt_rfk; struct rfkill *bt_rfk;
struct input_dev *hotkey_dev; struct input_dev *hotkey_dev;
int illumination_installed;
acpi_handle handle; acpi_handle handle;
const char *bt_name; const char *bt_name;
...@@ -294,6 +297,110 @@ struct toshiba_acpi_dev { ...@@ -294,6 +297,110 @@ struct toshiba_acpi_dev {
struct mutex mutex; 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 = { static struct toshiba_acpi_dev toshiba_acpi = {
.bt_name = "Toshiba Bluetooth", .bt_name = "Toshiba Bluetooth",
}; };
...@@ -913,6 +1020,9 @@ static void toshiba_acpi_exit(void) ...@@ -913,6 +1020,9 @@ static void toshiba_acpi_exit(void)
acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY, acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
toshiba_acpi_notify); toshiba_acpi_notify);
if (toshiba_acpi.illumination_installed)
led_classdev_unregister(&toshiba_led);
platform_device_unregister(toshiba_acpi.p_dev); platform_device_unregister(toshiba_acpi.p_dev);
return; return;
...@@ -1007,6 +1117,13 @@ static int __init toshiba_acpi_init(void) ...@@ -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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment