From: Yong Wang <yong.y.wang@linux.intel.com>
To: Matthew Garrett <mjg@redhat.com>,
Dmitry Torokhov <dmitry.torokhov@gmail.com>,
Corentin Chary <corentincj@iksaif.net>,
Richard Purdie <rpurdie@linux.intel.com>
Cc: platform-driver-x86@vger.kernel.org, linux-input@vger.kernel.org
Subject: [PATCH] eeepc-wmi: Add backlight support
Date: Wed, 7 Apr 2010 22:17:50 +0800 [thread overview]
Message-ID: <20100407141750.GA16896@ywang-moblin2.bj.intel.com> (raw)
Add backlight support for WMI based Eee PC laptops. In addition, start
to use a platform device to manage all functional devices as more
features will be implemented later.
Signed-off-by: Yong Wang <yong.y.wang@intel.com>
--
drivers/platform/x86/eeepc-wmi.c | 301 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 266 insertions(+), 35 deletions(-)
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 9f88226..19438ea 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -30,6 +30,9 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -38,6 +41,7 @@ MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
MODULE_LICENSE("GPL");
#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
+#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
@@ -46,6 +50,11 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
#define NOTIFY_BRNDOWN_MIN 0x20
#define NOTIFY_BRNDOWN_MAX 0x2e
+#define EEEPC_WMI_METHODID_DEVS 0x53564544
+#define EEEPC_WMI_METHODID_DSTS 0x53544344
+
+#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012
+
static const struct key_entry eeepc_wmi_keymap[] = {
/* Sleep already handled via generic ACPI code */
{ KE_KEY, 0x5d, { KEY_WLAN } },
@@ -58,7 +67,189 @@ static const struct key_entry eeepc_wmi_keymap[] = {
{ KE_END, 0},
};
+struct bios_args {
+ u32 dev_id;
+ u32 ctrl_param;
+};
+
+static struct platform_device *eeepc_wmi_platform_device;
static struct input_dev *eeepc_wmi_input_dev;
+struct backlight_device *eeepc_wmi_backlight_device;
+
+static int eeepc_wmi_input_init(void)
+{
+ int err;
+
+ eeepc_wmi_input_dev = input_allocate_device();
+ if (!eeepc_wmi_input_dev)
+ return -ENOMEM;
+
+ eeepc_wmi_input_dev->name = "Eee PC WMI hotkeys";
+ eeepc_wmi_input_dev->phys = "wmi/input0";
+ eeepc_wmi_input_dev->id.bustype = BUS_HOST;
+ eeepc_wmi_input_dev->dev.parent = &eeepc_wmi_platform_device->dev;
+
+ err = sparse_keymap_setup(eeepc_wmi_input_dev, eeepc_wmi_keymap, NULL);
+ if (err)
+ goto err_free_dev;
+
+ err = input_register_device(eeepc_wmi_input_dev);
+ if (err)
+ goto err_free_keymap;
+
+ return 0;
+
+err_free_keymap:
+ sparse_keymap_free(eeepc_wmi_input_dev);
+err_free_dev:
+ input_free_device(eeepc_wmi_input_dev);
+ return err;
+}
+
+static void eeepc_wmi_input_exit(void)
+{
+ if (eeepc_wmi_input_dev) {
+ sparse_keymap_free(eeepc_wmi_input_dev);
+ input_unregister_device(eeepc_wmi_input_dev);
+ }
+
+ eeepc_wmi_input_dev = NULL;
+}
+
+static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param)
+{
+ struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+ u32 tmp;
+
+ status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
+ 1, EEEPC_WMI_METHODID_DSTS, &input, &output);
+
+ if (ACPI_FAILURE(status))
+ return status;
+
+ obj = (union acpi_object *)output.pointer;
+ if (obj && obj->type == ACPI_TYPE_INTEGER) {
+ tmp = (u32)obj->integer.value;
+ } else {
+ tmp = 0;
+ }
+
+ if (ctrl_param)
+ *ctrl_param = tmp;
+
+ kfree(obj);
+
+ return status;
+
+}
+
+static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param)
+{
+ struct bios_args args = {
+ .dev_id = dev_id,
+ .ctrl_param = ctrl_param,
+ };
+ struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+ acpi_status status;
+
+ status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
+ 1, EEEPC_WMI_METHODID_DEVS, &input, NULL);
+
+ return status;
+}
+
+static int read_brightness(struct backlight_device *bd)
+{
+ static u32 ctrl_param;
+ acpi_status status;
+
+ status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &ctrl_param);
+
+ if (ACPI_FAILURE(status)) {
+ return -1;
+ } else {
+ return (ctrl_param & 0x000000FF);
+ }
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+
+ static u32 ctrl_param;
+ acpi_status status;
+
+ ctrl_param = bd->props.brightness;
+
+ status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, ctrl_param);
+
+ if (ACPI_FAILURE(status)) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+static struct backlight_ops eeepc_wmi_bl_ops = {
+ .get_brightness = read_brightness,
+ .update_status = update_bl_status,
+};
+
+static int eeepc_wmi_backlight_notify(bool increase)
+{
+ struct backlight_device *bd = eeepc_wmi_backlight_device;
+ int old = bd->props.brightness;
+ int new;
+
+ if (increase)
+ new = old + 1;
+ else
+ new = old - 1;
+
+ if (new > bd->props.max_brightness)
+ new = bd->props.max_brightness;
+ else if (new < 0)
+ new = 0;
+
+ bd->props.brightness = new;
+ backlight_update_status(bd);
+ backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
+
+ return old;
+}
+
+static int eeepc_wmi_backlight_init(void)
+{
+ struct backlight_device *bd;
+
+ bd = backlight_device_register("eeepc-wmi",
+ &eeepc_wmi_platform_device->dev, NULL,
+ &eeepc_wmi_bl_ops);
+ if (IS_ERR(bd)) {
+ pr_err("EEEPC WMI:Could not register backlight device\n");
+ eeepc_wmi_backlight_device = NULL;
+ return PTR_ERR(bd);
+ }
+
+ eeepc_wmi_backlight_device = bd;
+
+ bd->props.brightness = read_brightness(bd);
+ bd->props.max_brightness = 15;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
+
+ return 0;
+}
+
+static void eeepc_wmi_backlight_exit(void)
+{
+ if (eeepc_wmi_backlight_device)
+ backlight_device_unregister(eeepc_wmi_backlight_device);
+
+ eeepc_wmi_backlight_device = NULL;
+}
static void eeepc_wmi_notify(u32 value, void *context)
{
@@ -83,6 +274,11 @@ static void eeepc_wmi_notify(u32 value, void *context)
else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
code = NOTIFY_BRNDOWN_MIN;
+ if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
+ if (!acpi_video_backlight_support())
+ eeepc_wmi_backlight_notify(code == NOTIFY_BRNUP_MIN);
+ }
+
if (!sparse_keymap_report_event(eeepc_wmi_input_dev,
code, 1, true))
pr_info("EEEPC WMI: Unknown key %x pressed\n", code);
@@ -91,67 +287,102 @@ static void eeepc_wmi_notify(u32 value, void *context)
kfree(obj);
}
-static int eeepc_wmi_input_setup(void)
+static int __devinit eeepc_wmi_platform_probe(struct platform_device *device)
{
int err;
+ acpi_status status;
- eeepc_wmi_input_dev = input_allocate_device();
- if (!eeepc_wmi_input_dev)
- return -ENOMEM;
-
- eeepc_wmi_input_dev->name = "Eee PC WMI hotkeys";
- eeepc_wmi_input_dev->phys = "wmi/input0";
- eeepc_wmi_input_dev->id.bustype = BUS_HOST;
-
- err = sparse_keymap_setup(eeepc_wmi_input_dev, eeepc_wmi_keymap, NULL);
+ err = eeepc_wmi_input_init();
if (err)
- goto err_free_dev;
+ goto error_input;
- err = input_register_device(eeepc_wmi_input_dev);
- if (err)
- goto err_free_keymap;
+ if (!acpi_video_backlight_support()) {
+ err = eeepc_wmi_backlight_init();
+ if (err)
+ goto error_backlight;
+ } else
+ pr_info("EEEPC WMI: Backlight controlled by ACPI video driver\n");
+
+ status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
+ eeepc_wmi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ pr_err("EEEPC WMI: Unable to register notify handler - %d\n",
+ status);
+ err = -ENODEV;
+ goto error_wmi;
+ }
return 0;
-err_free_keymap:
- sparse_keymap_free(eeepc_wmi_input_dev);
-err_free_dev:
- input_free_device(eeepc_wmi_input_dev);
+error_wmi:
+ eeepc_wmi_backlight_exit();
+error_backlight:
+ eeepc_wmi_input_exit();
+error_input:
return err;
}
+static int __devexit eeepc_wmi_platform_remove(struct platform_device *device)
+{
+ wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
+ eeepc_wmi_backlight_exit();
+ eeepc_wmi_input_exit();
+
+ return 0;
+}
+
+static struct platform_driver platform_driver = {
+ .driver = {
+ .name = "eeepc-wmi",
+ .owner = THIS_MODULE,
+ },
+ .probe = eeepc_wmi_platform_probe,
+ .remove = __devexit_p(eeepc_wmi_platform_remove),
+};
+
static int __init eeepc_wmi_init(void)
{
int err;
- acpi_status status;
- if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID)) {
+ if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) {
pr_warning("EEEPC WMI: No known WMI GUID found\n");
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- err = eeepc_wmi_input_setup();
- if (err)
- return err;
+ eeepc_wmi_platform_device = platform_device_alloc("eeepc-wmi", -1);
+ if (!eeepc_wmi_platform_device) {
+ pr_warning("EEEPC WMI: Unable to allocate platform device\n");
+ err = -ENOMEM;
+ goto out;
+ }
- status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
- eeepc_wmi_notify, NULL);
- if (ACPI_FAILURE(status)) {
- sparse_keymap_free(eeepc_wmi_input_dev);
- input_unregister_device(eeepc_wmi_input_dev);
- pr_err("EEEPC WMI: Unable to register notify handler - %d\n",
- status);
- return -ENODEV;
+ err = platform_device_add(eeepc_wmi_platform_device);
+ if (err) {
+ pr_warning("EEEPC WMI: Unable to add platform device\n");
+ goto put_dev;
+ }
+
+ err = platform_driver_register(&platform_driver);
+ if (err) {
+ pr_warning("EEEPC WMI: Unable to register platform driver\n");
+ goto del_dev;
}
return 0;
+
+del_dev:
+ platform_device_del(eeepc_wmi_platform_device);
+put_dev:
+ platform_device_put(eeepc_wmi_platform_device);
+out:
+ return err;
}
static void __exit eeepc_wmi_exit(void)
{
- wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
- sparse_keymap_free(eeepc_wmi_input_dev);
- input_unregister_device(eeepc_wmi_input_dev);
+ platform_driver_unregister(&platform_driver);
+ platform_device_unregister(eeepc_wmi_platform_device);
}
module_init(eeepc_wmi_init);
next reply other threads:[~2010-04-07 14:27 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-04-07 14:17 Yong Wang [this message]
2010-04-07 15:05 ` [PATCH] eeepc-wmi: Add backlight support Corentin Chary
2010-04-07 22:50 ` Yong Wang
2010-04-08 5:29 ` Corentin Chary
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=20100407141750.GA16896@ywang-moblin2.bj.intel.com \
--to=yong.y.wang@linux.intel.com \
--cc=corentincj@iksaif.net \
--cc=dmitry.torokhov@gmail.com \
--cc=linux-input@vger.kernel.org \
--cc=mjg@redhat.com \
--cc=platform-driver-x86@vger.kernel.org \
--cc=rpurdie@linux.intel.com \
/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.