Commit 6c3f6e6c575a0a992429427d4978c6091756a526

Authored by Pierre Ducroquet
Committed by Matthew Garrett
1 parent 5ca5671891

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>

Showing 1 changed file with 117 additions and 0 deletions Side-by-side Diff

drivers/platform/x86/toshiba_acpi.c
... ... @@ -4,6 +4,7 @@
4 4 *
5 5 * Copyright (C) 2002-2004 John Belmonte
6 6 * Copyright (C) 2008 Philip Langdale
  7 + * Copyright (C) 2010 Pierre Ducroquet
7 8 *
8 9 * This program is free software; you can redistribute it and/or modify
9 10 * it under the terms of the GNU General Public License as published by
... ... @@ -47,6 +48,7 @@
47 48 #include <linux/platform_device.h>
48 49 #include <linux/rfkill.h>
49 50 #include <linux/input.h>
  51 +#include <linux/leds.h>
50 52 #include <linux/slab.h>
51 53  
52 54 #include <asm/uaccess.h>
... ... @@ -287,6 +289,7 @@
287 289 struct platform_device *p_dev;
288 290 struct rfkill *bt_rfk;
289 291 struct input_dev *hotkey_dev;
  292 + int illumination_installed;
290 293 acpi_handle handle;
291 294  
292 295 const char *bt_name;
... ... @@ -294,6 +297,110 @@
294 297 struct mutex mutex;
295 298 };
296 299  
  300 +/* Illumination support */
  301 +static int toshiba_illumination_available(void)
  302 +{
  303 + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
  304 + u32 out[HCI_WORDS];
  305 + acpi_status status;
  306 +
  307 + in[0] = 0xf100;
  308 + status = hci_raw(in, out);
  309 + if (ACPI_FAILURE(status)) {
  310 + printk(MY_INFO "Illumination device not available\n");
  311 + return 0;
  312 + }
  313 + in[0] = 0xf400;
  314 + status = hci_raw(in, out);
  315 + return 1;
  316 +}
  317 +
  318 +static void toshiba_illumination_set(struct led_classdev *cdev,
  319 + enum led_brightness brightness)
  320 +{
  321 + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
  322 + u32 out[HCI_WORDS];
  323 + acpi_status status;
  324 +
  325 + /* First request : initialize communication. */
  326 + in[0] = 0xf100;
  327 + status = hci_raw(in, out);
  328 + if (ACPI_FAILURE(status)) {
  329 + printk(MY_INFO "Illumination device not available\n");
  330 + return;
  331 + }
  332 +
  333 + if (brightness) {
  334 + /* Switch the illumination on */
  335 + in[0] = 0xf400;
  336 + in[1] = 0x14e;
  337 + in[2] = 1;
  338 + status = hci_raw(in, out);
  339 + if (ACPI_FAILURE(status)) {
  340 + printk(MY_INFO "ACPI call for illumination failed.\n");
  341 + return;
  342 + }
  343 + } else {
  344 + /* Switch the illumination off */
  345 + in[0] = 0xf400;
  346 + in[1] = 0x14e;
  347 + in[2] = 0;
  348 + status = hci_raw(in, out);
  349 + if (ACPI_FAILURE(status)) {
  350 + printk(MY_INFO "ACPI call for illumination failed.\n");
  351 + return;
  352 + }
  353 + }
  354 +
  355 + /* Last request : close communication. */
  356 + in[0] = 0xf200;
  357 + in[1] = 0;
  358 + in[2] = 0;
  359 + hci_raw(in, out);
  360 +}
  361 +
  362 +static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
  363 +{
  364 + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
  365 + u32 out[HCI_WORDS];
  366 + acpi_status status;
  367 + enum led_brightness result;
  368 +
  369 + /* First request : initialize communication. */
  370 + in[0] = 0xf100;
  371 + status = hci_raw(in, out);
  372 + if (ACPI_FAILURE(status)) {
  373 + printk(MY_INFO "Illumination device not available\n");
  374 + return LED_OFF;
  375 + }
  376 +
  377 + /* Check the illumination */
  378 + in[0] = 0xf300;
  379 + in[1] = 0x14e;
  380 + status = hci_raw(in, out);
  381 + if (ACPI_FAILURE(status)) {
  382 + printk(MY_INFO "ACPI call for illumination failed.\n");
  383 + return LED_OFF;
  384 + }
  385 +
  386 + result = out[2] ? LED_FULL : LED_OFF;
  387 +
  388 + /* Last request : close communication. */
  389 + in[0] = 0xf200;
  390 + in[1] = 0;
  391 + in[2] = 0;
  392 + hci_raw(in, out);
  393 +
  394 + return result;
  395 +}
  396 +
  397 +static struct led_classdev toshiba_led = {
  398 + .name = "toshiba::illumination",
  399 + .max_brightness = 1,
  400 + .brightness_set = toshiba_illumination_set,
  401 + .brightness_get = toshiba_illumination_get,
  402 +};
  403 +
297 404 static struct toshiba_acpi_dev toshiba_acpi = {
298 405 .bt_name = "Toshiba Bluetooth",
299 406 };
... ... @@ -913,6 +1020,9 @@
913 1020 acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
914 1021 toshiba_acpi_notify);
915 1022  
  1023 + if (toshiba_acpi.illumination_installed)
  1024 + led_classdev_unregister(&toshiba_led);
  1025 +
916 1026 platform_device_unregister(toshiba_acpi.p_dev);
917 1027  
918 1028 return;
... ... @@ -1005,6 +1115,13 @@
1005 1115 toshiba_acpi_exit();
1006 1116 return ret;
1007 1117 }
  1118 + }
  1119 +
  1120 + toshiba_acpi.illumination_installed = 0;
  1121 + if (toshiba_illumination_available()) {
  1122 + if (!led_classdev_register(&(toshiba_acpi.p_dev->dev),
  1123 + &toshiba_led))
  1124 + toshiba_acpi.illumination_installed = 1;
1008 1125 }
1009 1126  
1010 1127 return 0;