Re: [PATCH 4/4] eeepc-wmi: add backlight support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Apr 9, 2010 at 5:07 PM, Yong Wang <yong.y.wang@xxxxxxxxxxxxxxx> wrote:
> Add backlight support for WMI based Eee PC laptops.
>
> Signed-off-by: Yong Wang <yong.y.wang@xxxxxxxxx>
> ---
>  drivers/platform/x86/eeepc-wmi.c |  170 +++++++++++++++++++++++++++++++++++++-
>  1 files changed, 167 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
> index 0f5ab6a..784687c 100644
> --- a/drivers/platform/x86/eeepc-wmi.c
> +++ b/drivers/platform/x86/eeepc-wmi.c
> @@ -30,6 +30,8 @@
>  #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>
> @@ -39,14 +41,21 @@ 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);
> +MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
>
>  #define NOTIFY_BRNUP_MIN       0x11
>  #define NOTIFY_BRNUP_MAX       0x1f
>  #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 } },
> @@ -59,9 +68,15 @@ static const struct key_entry eeepc_wmi_keymap[] = {
>        { KE_END, 0},
>  };
>
> +struct bios_args {
> +       u32     dev_id;
> +       u32     ctrl_param;
> +};
> +
>  struct eeepc_wmi {
>        struct platform_device *platform_dev;
>        struct input_dev *input_dev;
> +       struct backlight_device *backlight_dev;
>  };

Same comment as before, here we use backlight_device in eeepc-laptop
and asus-laptop

>  static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc_wmi)
> @@ -104,6 +119,139 @@ static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc_wmi)
>        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);

Small indent error here.

> +       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;
> +}

ctrl_param & 0xFF seems simpler

> +
> +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 const struct backlight_ops eeepc_wmi_bl_ops = {
> +       .get_brightness = read_brightness,
> +       .update_status = update_bl_status,
> +};
> +
> +static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc_wmi, bool increase)
> +{
> +       struct backlight_device *bd = eeepc_wmi->backlight_dev;
> +       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);

Do you really need to do that ? Can't you just use read_backlight()
and do nothing (just call backlight_force_update) ?
If you really need to do that (but I don't think so), can't you just
do "new = event -   NOTIFY_BRN_MIN" ?

> +       backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
> +
> +       return old;
> +}
> +
> +static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc_wmi)
> +{
> +       struct backlight_device *bd;
> +       struct backlight_properties props;
> +
> +       memset(&props, 0, sizeof(struct backlight_properties));
> +       props.max_brightness = 15;
> +       bd = backlight_device_register("eeepc-wmi",

You could use a macro for "eeepc-wmi"
(see my previous comment in patch 3/4)

> +                                      &eeepc_wmi->platform_dev->dev, eeepc_wmi,
> +                                      &eeepc_wmi_bl_ops, &props);
> +       if (IS_ERR(bd)) {
> +               pr_err("EEEPC WMI:Could not register backlight device\n");
> +               return PTR_ERR(bd);
> +       }
> +
> +       eeepc_wmi->backlight_dev = bd;
> +
> +       bd->props.brightness = read_brightness(bd);
> +       bd->props.power = FB_BLANK_UNBLANK;
> +       backlight_update_status(bd);
> +
> +       return 0;
> +}
> +
> +static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc_wmi)
> +{
> +       if (eeepc_wmi->backlight_dev)
> +               backlight_device_unregister(eeepc_wmi->backlight_dev);
> +
> +       eeepc_wmi->backlight_dev = NULL;
> +}
> +
>  static void eeepc_wmi_notify(u32 value, void *context)
>  {
>        struct eeepc_wmi *eeepc_wmi = (struct eeepc_wmi *)context;
> @@ -128,6 +276,12 @@ 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(eeepc_wmi,
> +                                                          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);
> @@ -146,7 +300,14 @@ static int __devinit eeepc_wmi_platform_probe(struct platform_device *device)
>
>        err = eeepc_wmi_input_init(eeepc_wmi);
>        if (err)
> -               return err;
> +               goto error_input;
> +
> +       if (!acpi_video_backlight_support()) {
> +               err = eeepc_wmi_backlight_init(eeepc_wmi);
> +               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, eeepc_wmi);
> @@ -160,8 +321,10 @@ static int __devinit eeepc_wmi_platform_probe(struct platform_device *device)
>        return 0;
>
>  error_wmi:
> +       eeepc_wmi_backlight_exit(eeepc_wmi);
> +error_backlight:
>        eeepc_wmi_input_exit(eeepc_wmi);
> -
> +error_input:
>        return err;
>  }
>
> @@ -171,6 +334,7 @@ static int __devexit eeepc_wmi_platform_remove(struct platform_device *device)
>
>        eeepc_wmi = wmi_get_driver_data(EEEPC_WMI_EVENT_GUID);
>        wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
> +       eeepc_wmi_backlight_exit(eeepc_wmi);
>        eeepc_wmi_input_exit(eeepc_wmi);
>
>        return 0;
> @@ -190,7 +354,7 @@ static int __init eeepc_wmi_init(void)
>        struct eeepc_wmi *eeepc_wmi;
>        int err;
>
> -       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;
>        }

Maybe you could make the driver work only for the available GUID. If
EVENT_GUID is here, provide hotkeys.
If MGMT is here, provide extra functions. And if none are there, return -ENODEV;

-- 
Corentin Chary
http://xf.iksaif.net
--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux