All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Tuttle <thinkinginbinary@gmail.com>
To: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Cc: Richard Purdie <rpurdie@rpsys.net>
Subject: [PATCH] Integrate asus_acpi LED's with new LED subsystem
Date: Thu, 6 Jul 2006 15:31:57 -0400	[thread overview]
Message-ID: <20060706193157.GC14043@phoenix> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 561 bytes --]

(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>

[-- Attachment #1.2: asus-acpi-led-subsystem.patch --]
[-- Type: text/plain, Size: 7583 bytes --]

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

[-- Attachment #2: Type: application/pgp-signature, Size: 191 bytes --]

             reply	other threads:[~2006-07-06 19:32 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-06 19:31 Thomas Tuttle [this message]
2006-07-06 22:39 ` [PATCH] Integrate asus_acpi LED's with new LED subsystem Richard Purdie
2006-07-07  1:11   ` Thomas Tuttle
2006-07-06 22:49 ` Andrew Morton
2006-07-07  1:20   ` Thomas Tuttle
2006-07-07  8:46     ` Richard Purdie
2006-07-24 21:24     ` Johannes Engel
2006-07-06 23:50 ` Pavel Machek
2006-07-07  1:44   ` Thomas Tuttle
2006-07-07  9:38     ` Pavel Machek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060706193157.GC14043@phoenix \
    --to=thinkinginbinary@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rpurdie@rpsys.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.