Hi A friend of mine owns a Toshiba Qosmio G55, which include some LEDs illuminating the keyboard. Toshiba calls that technology "illumination", and doesn't provide any Linux driver nor documentation. After reverse engineering the Windows driver, I got a patch for the toshiba_acpi driver that adds support for this hardware. Is this the right mailing list to send this patch ? I attached it to this mail. Do not hesitate to comment it. I know the hardcoded hexadecimal values are stranges, but I didn't find their meaning, I only know that they have to be used in that order, and that any missing call will make it fail. Of course, if this is not the right procedure or the right place, please correct me. Thanks Pierre Ducroquet.
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 37aa147..f3a0d95 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> @@ -285,6 +287,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; @@ -292,6 +295,111 @@ 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 "The illumination device available is 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 "The illumination device available is 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 "The illumination device available is 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", }; @@ -845,7 +953,7 @@ static int toshiba_acpi_setup_keyboard(char *device) acpi_handle handle; int result; const struct key_entry *key; - + status = acpi_get_handle(NULL, device, &handle); if (ACPI_FAILURE(status)) { printk(MY_INFO "Unable to get notification device\n"); @@ -853,7 +961,7 @@ static int toshiba_acpi_setup_keyboard(char *device) } toshiba_acpi.handle = handle; - + status = acpi_evaluate_object(handle, "ENAB", NULL, NULL); if (ACPI_FAILURE(status)) { printk(MY_INFO "Unable to enable hotkeys\n"); @@ -903,6 +1011,10 @@ static void toshiba_acpi_exit(void) rfkill_destroy(toshiba_acpi.bt_rfk); } + if (toshiba_acpi.illumination_installed) { + led_classdev_unregister(&toshiba_led); + } + if (toshiba_backlight_device) backlight_device_unregister(toshiba_backlight_device); @@ -1012,6 +1124,12 @@ static int __init toshiba_acpi_init(void) return ret; } } + + 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; }
Attachment:
signature.asc
Description: This is a digitally signed message part.