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