lkml.org 
[lkml]   [2006]   [Jul]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] Integrate asus_acpi LED's with new LED subsystem
    (Sorry to repost... just going through the motions of ChangeLog and
    Signed-off-by headers.)

    Here is a patch to the asus_acpi driver that links the Asus laptop LED's
    into the new LED subsystem. It creates LED class devices named
    asus:mail, asus:wireless, and asus:touchpad, depending on if the laptop
    supports the mled, wled, and tled LED's.

    Since it's so new, I added a config option to turn it on and off. It's
    worked for me, though I have an Asus M2N, which only has the mail and
    wireless LED's.

    Signed-off-by: Thomas Tuttle <thinkinginbinary@gmail.com>
    diff -udrN linux-2.6.17-git25/drivers/acpi/asus_acpi.c linux-2.6.17-git25-mine/drivers/acpi/asus_acpi.c
    --- linux-2.6.17-git25/drivers/acpi/asus_acpi.c 2006-07-05 22:11:37.000000000 -0400
    +++ linux-2.6.17-git25-mine/drivers/acpi/asus_acpi.c 2006-07-05 22:26:51.000000000 -0400
    @@ -27,14 +27,19 @@
    * Johann Wiesner - Small compile fixes
    * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
    * �ric Burghard - LED display support for W1N
    + * Thomas Tuttle - LED subsystem integration
    *
    */

    +#include <linux/config.h>
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/types.h>
    #include <linux/proc_fs.h>
    +#ifdef CONFIG_ACPI_ASUS_NEW_LED
    +#include <linux/leds.h>
    +#endif
    #include <acpi/acpi_drivers.h>
    #include <acpi/acpi_bus.h>
    #include <asm/uaccess.h>
    @@ -916,6 +921,145 @@
    return 0;
    }

    +#ifdef CONFIG_ACPI_ASUS_NEW_LED
    +
    +/* These functions are called by the LED subsystem to update the desired
    + * state of the LED's. */
    +static void led_set_mled(struct led_classdev *led_cdev,
    + enum led_brightness value);
    +static void led_set_wled(struct led_classdev *led_cdev,
    + enum led_brightness value);
    +static void led_set_tled(struct led_classdev *led_cdev,
    + enum led_brightness value);
    +
    +/* LED class devices. */
    +static struct led_classdev led_cdev_mled =
    + { .name = "asus:mail", .brightness_set = led_set_mled };
    +static struct led_classdev led_cdev_wled =
    + { .name = "asus:wireless", .brightness_set = led_set_wled };
    +static struct led_classdev led_cdev_tled =
    + { .name = "asus:touchpad", .brightness_set = led_set_tled };
    +
    +/* These functions actually update the LED's, and are called from a
    + * workqueue. By doing this as separate work rather than when the LED
    + * subsystem asks, I avoid messing with the Asus ACPI stuff during a
    + * potentially bad time, such as a timer interrupt. */
    +static void led_update_mled(void *private);
    +static void led_update_wled(void *private);
    +static void led_update_tled(void *private);
    +
    +/* Desired values of LED's. */
    +static int led_mled_value = 0;
    +static int led_wled_value = 0;
    +static int led_tled_value = 0;
    +
    +/* LED workqueue. */
    +static struct workqueue_struct *led_workqueue;
    +
    +/* LED update work structs. */
    +DECLARE_WORK(led_mled_work, led_update_mled, NULL);
    +DECLARE_WORK(led_wled_work, led_update_wled, NULL);
    +DECLARE_WORK(led_tled_work, led_update_tled, NULL);
    +
    +/* LED subsystem callbacks. */
    +static void led_set_mled(struct led_classdev *led_cdev,
    + enum led_brightness value)
    +{
    + led_mled_value = value;
    + queue_work(led_workqueue, &led_mled_work);
    +}
    +
    +static void led_set_wled(struct led_classdev *led_cdev,
    + enum led_brightness value)
    +{
    + led_wled_value = value;
    + queue_work(led_workqueue, &led_wled_work);
    +}
    +
    +static void led_set_tled(struct led_classdev *led_cdev,
    + enum led_brightness value)
    +{
    + led_tled_value = value;
    + queue_work(led_workqueue, &led_tled_work);
    +}
    +
    +/* LED work functions. */
    +static void led_update_mled(void *private) {
    + char *ledname = hotk->methods->mt_mled;
    + int led_out = led_mled_value ? 1 : 0;
    + hotk->status = (led_out) ? (hotk->status | MLED_ON) : (hotk->status & ~MLED_ON);
    + led_out = 1 - led_out;
    + if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
    + printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
    + ledname);
    +}
    +
    +static void led_update_wled(void *private) {
    + char *ledname = hotk->methods->mt_wled;
    + int led_out = led_wled_value ? 1 : 0;
    + hotk->status = (led_out) ? (hotk->status | WLED_ON) : (hotk->status & ~WLED_ON);
    + if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
    + printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
    + ledname);
    +}
    +
    +static void led_update_tled(void *private) {
    + char *ledname = hotk->methods->mt_tled;
    + int led_out = led_tled_value ? 1 : 0;
    + hotk->status = (led_out) ? (hotk->status | TLED_ON) : (hotk->status & ~TLED_ON);
    + if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
    + printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
    + ledname);
    +}
    +
    +/* Registers LED class devices and sets up workqueue. */
    +static int led_initialize(struct device *parent)
    +{
    + int result;
    +
    + if (hotk->methods->mt_mled) {
    + result = led_classdev_register(parent, &led_cdev_mled);
    + if (result)
    + return result;
    + }
    +
    + if (hotk->methods->mt_wled) {
    + result = led_classdev_register(parent, &led_cdev_wled);
    + if (result)
    + return result;
    + }
    +
    + if (hotk->methods->mt_tled) {
    + result = led_classdev_register(parent, &led_cdev_tled);
    + if (result)
    + return result;
    + }
    +
    + led_workqueue = create_singlethread_workqueue("led_workqueue");
    +
    + return 0;
    +}
    +
    +/* Destroys the workqueue and unregisters the LED class devices. */
    +static void led_terminate(void)
    +{
    + destroy_workqueue(led_workqueue);
    +
    + if (hotk->methods->mt_tled) {
    + led_classdev_unregister(&led_cdev_tled);
    + }
    +
    + if (hotk->methods->mt_wled) {
    + led_classdev_unregister(&led_cdev_wled);
    + }
    +
    + if (hotk->methods->mt_mled) {
    + led_classdev_unregister(&led_cdev_mled);
    + }
    +}
    +
    +#endif
    +
    static int asus_hotk_add_fs(struct acpi_device *device)
    {
    struct proc_dir_entry *proc;
    @@ -1299,6 +1443,10 @@
    /* LED display is off by default */
    hotk->ledd_status = 0xFFF;

    +#ifdef CONFIG_ACPI_ASUS_NEW_LED
    + result = led_initialize(acpi_get_physical_device(device->handle));
    +#endif
    +
    end:
    if (result) {
    kfree(hotk);
    @@ -1314,6 +1462,10 @@
    if (!device || !acpi_driver_data(device))
    return -EINVAL;

    +#ifdef CONFIG_ACPI_ASUS_NEW_LED
    + led_terminate();
    +#endif
    +
    status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
    asus_hotk_notify);
    if (ACPI_FAILURE(status))
    diff -udrN linux-2.6.17-git25/drivers/acpi/Kconfig linux-2.6.17-git25-mine/drivers/acpi/Kconfig
    --- linux-2.6.17-git25/drivers/acpi/Kconfig 2006-07-05 22:44:33.000000000 -0400
    +++ linux-2.6.17-git25-mine/drivers/acpi/Kconfig 2006-07-05 22:44:43.000000000 -0400
    @@ -199,6 +199,15 @@
    something works not quite as expected, please use the mailing list
    available on the above page (acpi4asus-user@lists.sourceforge.net)

    +config ACPI_ASUS_NEW_LED
    + bool "ASUS/Medion LED subsystem integration"
    + depends on ACPI_ASUS
    + depends on LEDS_CLASS
    + help
    + This adds support for the new LED subsystem to the asus_acpi
    + driver. The LED's will show up as asus:mail, asus:wireless,
    + and asus:touchpad, as applicable to your laptop.
    +
    config ACPI_IBM
    tristate "IBM ThinkPad Laptop Extras"
    depends on X86[unhandled content-type:application/pgp-signature]
    \
     
     \ /
      Last update: 2006-07-06 21:35    [W:0.051 / U:1.552 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site