Hi Dmitry,

於 五,2010-10-01 於 09:58 -0700,Dmitry Torokhov 提到:
> Hi Lee,
> 
> On Fri, Oct 01, 2010 at 09:51:27PM +0800, Lee, Chun-Yi wrote:
> > +
> > +struct key_entry {
> > +   char type;      /* See KE_* below */
> > +   u16 code;
> > +   u16 keycode;
> > +};
> > +
> > +enum { KE_KEY, KE_END };
> > +
> 
> Like Corentin said, please use sparse_keymap, it will cut the code in
> half.
> 

Thank's for your and Corentin's suggestion, I already used sparse keymap
framework.

> > +
> > +   set_bit(EV_SW, acer_wmi_input_dev->evbit);
> > +
> 
> I do not see you sending SW_* events...
> 
> > +   err = input_register_device(acer_wmi_input_dev);
> > +
> > +   if (err) {
> > +           input_free_device(acer_wmi_input_dev);
> > +           return err;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> >  /*
> >   * debugfs functions
> >   */
> > @@ -1327,6 +1518,18 @@ static int __init acer_wmi_init(void)
> >                    "generic video driver\n");
> >     }
> >  
> > +   if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
> > +           err = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
> > +                                           acer_wmi_notify, NULL);
> > +           if (ACPI_FAILURE(err))
> > +                   return -EINVAL;
> > +           err = acer_wmi_input_setup();
> 
> You really want to set up the device first and install notify handler
> later. What will happen if event will fire up while input device has not
> been created yet?
> 
> > +           if (err) {
> > +                   wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
> > +                   return err;
> > +           }
> > +   }
> > +
> >     err = platform_driver_register(&acer_platform_driver);
> >     if (err) {
> >             printk(ACER_ERR "Unable to register platform driver.\n");
> > @@ -1368,11 +1571,21 @@ error_device_add:
> >  error_device_alloc:
> >     platform_driver_unregister(&acer_platform_driver);
> >  error_platform_register:
> > +   if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
> > +           input_unregister_device(acer_wmi_input_dev);
> > +           wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
> 
> Same here, first shut off notified, then remove the device.
> 
> > +   }
> > +
> >     return err;
> >  }
> >  
> >  static void __exit acer_wmi_exit(void)
> >  {
> > +   if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
> > +           wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
> > +           input_unregister_device(acer_wmi_input_dev);
> 
> Same here.
> 
> Thanks.
> 

Thank's for your review, I modified 2 patches like the following. I also
attached those 2 patches on this mail.

Thank's a lot
Joey Lee

>From 0e6f011a9a2219a47c93aa68433ba457ae1068e5 Mon Sep 17 00:00:00 2001
From: Lee, Chun-Yi <[email protected]>
Date: Tue, 12 Oct 2010 09:26:29 +0800
Subject: [PATCH 1/2] Add acer wmi hotkey events support

Add acer wmi hotkey event support. Install a wmi notify handler to
transfer wmi event key to key code, then send out keycode through acer
wmi input device to userland.

Signed-off-by: Lee, Chun-Yi <[email protected]>
---
 drivers/platform/x86/Kconfig    |    2 +
 drivers/platform/x86/acer-wmi.c |  139
+++++++++++++++++++++++++++++++++++++++
 2 files changed, 141 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2..c242fdd 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -23,7 +23,9 @@ config ACER_WMI
        depends on BACKLIGHT_CLASS_DEVICE
        depends on SERIO_I8042
        depends on RFKILL || RFKILL = n
+       depends on INPUT
        select ACPI_WMI
+       select INPUT_SPARSEKMAP
        ---help---
          This is a driver for newer Acer (and Wistron) laptops. It adds
          wireless radio and bluetooth control, and on some laptops,
diff --git a/drivers/platform/x86/acer-wmi.c
b/drivers/platform/x86/acer-wmi.c
index 2badee2..32285f4 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -37,6 +37,8 @@
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 
 #include <acpi/acpi_drivers.h>
 
@@ -48,6 +50,7 @@ MODULE_LICENSE("GPL");
 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
+#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
 
 /*
  * Magic Number
@@ -83,8 +86,39 @@ MODULE_LICENSE("GPL");
 #define WMID_GUID1             "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
 #define WMID_GUID2             "95764E09-FB56-4e83-B31A-37761F60994A"
 
+/*
+ * Acer ACPI event GUIDs
+ */
+#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
+
 MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
 MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
+MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
+
+enum acer_wmi_event_ids {
+       WMID_HOTKEY_EVENT = 0x1,
+};
+
+static const struct key_entry acer_wmi_keymap[] = {
+       {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
+       {KE_KEY, 0x12, {KEY_BLUETOOTH} },       /* BT */
+       {KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
+       {KE_KEY, 0x22, {KEY_PROG2} },    /* Aracade */
+       {KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
+       {KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
+       {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
+       {KE_KEY, 0x82, {KEY_F22} },      /* Touch Pad On/Off */
+       {KE_END, 0}
+};
+
+static struct input_dev *acer_wmi_input_dev;
+
+struct event_return_value {
+       u8 function;
+       u8 key_num;
+       u16 device_state;
+       u32 reserved;
+} __attribute__((packed));
 
 /*
  * Interface capability flags
@@ -1085,6 +1119,99 @@ static ssize_t show_interface(struct device *dev,
struct device_attribute *attr,
 
 static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
 
+static void acer_wmi_notify(u32 value, void *context)
+{
+       struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       struct event_return_value return_value;
+       acpi_status status;
+
+       status = wmi_get_event_data(value, &response);
+       if (status != AE_OK) {
+               printk(ACER_WARNING "bad event status 0x%x\n", status);
+               return;
+       }
+
+       obj = (union acpi_object *)response.pointer;
+
+       if (!obj)
+               return;
+       if (obj->type != ACPI_TYPE_BUFFER) {
+               printk(ACER_WARNING "Unknown response received %d\n",
+                       obj->type);
+               kfree(obj);
+               return;
+       }
+       if (obj->buffer.length != 8) {
+               printk(ACER_WARNING "Unknown buffer length %d\n",
+                       obj->buffer.length);
+               kfree(obj);
+               return;
+       }
+
+       return_value = *((struct event_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       switch (return_value.function) {
+       case WMID_HOTKEY_EVENT:
+               if (!sparse_keymap_report_event(acer_wmi_input_dev,
+                               return_value.key_num, 1, true))
+                       printk(ACER_WARNING "Unknown key number - 0x%x\n",
+                               return_value.key_num);
+               break;
+       default:
+               printk(ACER_WARNING "Unknown function number - %d - %d\n",
+                       return_value.function, return_value.key_num);
+               break;
+       }
+}
+
+static int __init acer_wmi_input_setup(void)
+{
+       acpi_status status;
+       int err;
+
+       acer_wmi_input_dev = input_allocate_device();
+       if (!acer_wmi_input_dev)
+               return -ENOMEM;
+
+       acer_wmi_input_dev->name = "Acer WMI hotkeys";
+       acer_wmi_input_dev->phys = "wmi/input0";
+       acer_wmi_input_dev->id.bustype = BUS_HOST;
+
+       err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
+       if (err)
+               goto err_free_dev;
+
+       err = input_register_device(acer_wmi_input_dev);
+       if (err)
+               goto err_free_keymap;
+
+       status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
+                                               acer_wmi_notify, NULL);
+       if (ACPI_FAILURE(status)) {
+               err = -EIO;
+               goto err_unregister_input;
+       }
+
+       return 0;
+
+err_unregister_input:
+       input_unregister_device(acer_wmi_input_dev);
+err_free_keymap:
+       sparse_keymap_free(acer_wmi_input_dev);
+err_free_dev:
+       input_free_device(acer_wmi_input_dev);
+       return err;
+}
+
+static void acer_wmi_input_destroy(void)
+{
+       wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
+       sparse_keymap_free(acer_wmi_input_dev);
+       input_unregister_device(acer_wmi_input_dev);
+}
+
 /*
  * debugfs functions
  */
@@ -1327,6 +1454,12 @@ static int __init acer_wmi_init(void)
                       "generic video driver\n");
        }
 
+       if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
+               err = acer_wmi_input_setup();
+               if (err)
+                       return err;
+       }
+
        err = platform_driver_register(&acer_platform_driver);
        if (err) {
                printk(ACER_ERR "Unable to register platform driver.\n");
@@ -1368,11 +1501,17 @@ error_device_add:
 error_device_alloc:
        platform_driver_unregister(&acer_platform_driver);
 error_platform_register:
+       if (wmi_has_guid(ACERWMID_EVENT_GUID))
+               acer_wmi_input_destroy();
+
        return err;
 }
 
 static void __exit acer_wmi_exit(void)
 {
+       if (wmi_has_guid(ACERWMID_EVENT_GUID))
+               acer_wmi_input_destroy();
+
        remove_sysfs(acer_platform_device);
        remove_debugfs();
        platform_device_unregister(acer_platform_device);
-- 
1.6.0.2

>From 1957b6b7cd071de95c0e1fb0e35cd5c9c9332630 Mon Sep 17 00:00:00 2001
From: Lee, Chun-Yi <[email protected]>
Date: Tue, 12 Oct 2010 09:27:23 +0800
Subject: [PATCH 2/2] Support enable Acer Launch Manager mode

Add a launch_manager parameter for support to enable Acer Launch Manager
mode. After enable it, the communication key will stop the default
behavior to control WLAN/Bluetooth/WWAN rfkill state. It leave usernland
application to handle the rfkill state changed.

Signed-off-by: Lee, Chun-Yi <[email protected]>
---
 drivers/platform/x86/acer-wmi.c |   74
+++++++++++++++++++++++++++++++++++++++
 1 files changed, 74 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/x86/acer-wmi.c
b/drivers/platform/x86/acer-wmi.c
index 32285f4..a28a775 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -85,6 +85,7 @@ MODULE_LICENSE("GPL");
 #define AMW0_GUID2             "431F16ED-0C2B-444C-B267-27DEB140CF9C"
 #define WMID_GUID1             "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
 #define WMID_GUID2             "95764E09-FB56-4e83-B31A-37761F60994A"
+#define WMID_GUID3             "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
 
 /*
  * Acer ACPI event GUIDs
@@ -120,6 +121,20 @@ struct event_return_value {
        u32 reserved;
 } __attribute__((packed));
 
+struct lm_input_params {
+       u8 function_num;        /* Function Number */
+       u16 commun_devices;     /* Communication type devices default status */
+       u16 devices;            /* Other type devices default status */
+       u8 lm_status;           /* Launch Manager Status */
+       u16 reserved;
+} __attribute__((packed));
+
+struct lm_return_value {
+       u8 error_code;          /* Error Code */
+       u8 ec_return_value;     /* EC Return Value */
+       u16 reserved;
+} __attribute__((packed));
+
 /*
  * Interface capability flags
  */
@@ -150,15 +165,18 @@ static int mailled = -1;
 static int brightness = -1;
 static int threeg = -1;
 static int force_series;
+static bool launch_manager;
 
 module_param(mailled, int, 0444);
 module_param(brightness, int, 0444);
 module_param(threeg, int, 0444);
 module_param(force_series, int, 0444);
+module_param(launch_manager, bool, 0444);
 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
 MODULE_PARM_DESC(force_series, "Force a different laptop series");
+MODULE_PARM_DESC(launch_manager, "Enable Acer Launch Manager mode");
 
 struct acer_data {
        int mailled;
@@ -1393,6 +1411,53 @@ error_debugfs:
        return -ENOMEM;
 }
 
+static int acer_wmi_enable_lm(void)
+{
+       struct lm_return_value return_value;
+       acpi_status status;
+       union acpi_object *obj;
+       struct lm_input_params params = {
+               .function_num = 0x1,
+               .commun_devices = 0x0041,       /* WiFi on, 3G on, BT off */
+               .devices = 0xFFFF,
+               .lm_status = 0x41,              /* Launch Manager Active */
+       };
+
+       struct acpi_buffer input = { sizeof(struct lm_input_params),
&params };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output.pointer;
+
+       if (!obj)
+               return -EINVAL;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return -EINVAL;
+       }
+       if (obj->buffer.length != 4) {
+               printk(ACER_WARNING "Unknown buffer length %d\n",
+                       obj->buffer.length);
+               kfree(obj);
+               return -EINVAL;
+       }
+
+       return_value = *((struct lm_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value)
+               printk(ACER_WARNING "Enabling Launch Manager failed: "
+                       "0x%x - 0x%x\n", return_value.error_code,
+                       return_value.ec_return_value);
+       else
+               printk(ACER_INFO "Enabled Launch Manager");
+
+       return status;
+}
+
 static int __init acer_wmi_init(void)
 {
        int err;
@@ -1454,6 +1519,15 @@ static int __init acer_wmi_init(void)
                       "generic video driver\n");
        }
 
+       if (wmi_has_guid(WMID_GUID3) && launch_manager) {
+               if (ACPI_FAILURE(acer_wmi_enable_lm())) {
+                       printk(ACER_ERR "Cannot enable Launch Manager mode\n");
+                       return -ENODEV;
+               }
+       } else if (!wmi_has_guid(WMID_GUID3) && launch_manager) {
+               printk(ACER_INFO "No WMID launch manager enable method\n");
+       }
+
        if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
                err = acer_wmi_input_setup();
                if (err)
-- 
1.6.0.2





>From 0e6f011a9a2219a47c93aa68433ba457ae1068e5 Mon Sep 17 00:00:00 2001
From: Lee, Chun-Yi <[email protected]>
Date: Tue, 12 Oct 2010 09:26:29 +0800
Subject: [PATCH 1/2] Add acer wmi hotkey events support

Add acer wmi hotkey event support. Install a wmi notify handler to
transfer wmi event key to key code, then send out keycode through acer
wmi input device to userland.

Signed-off-by: Lee, Chun-Yi <[email protected]>
---
 drivers/platform/x86/Kconfig    |    2 +
 drivers/platform/x86/acer-wmi.c |  139 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 141 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2..c242fdd 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -23,7 +23,9 @@ config ACER_WMI
        depends on BACKLIGHT_CLASS_DEVICE
        depends on SERIO_I8042
        depends on RFKILL || RFKILL = n
+       depends on INPUT
        select ACPI_WMI
+       select INPUT_SPARSEKMAP
        ---help---
          This is a driver for newer Acer (and Wistron) laptops. It adds
          wireless radio and bluetooth control, and on some laptops,
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 2badee2..32285f4 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -37,6 +37,8 @@
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 
 #include <acpi/acpi_drivers.h>
 
@@ -48,6 +50,7 @@ MODULE_LICENSE("GPL");
 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
+#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
 
 /*
  * Magic Number
@@ -83,8 +86,39 @@ MODULE_LICENSE("GPL");
 #define WMID_GUID1             "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
 #define WMID_GUID2             "95764E09-FB56-4e83-B31A-37761F60994A"
 
+/*
+ * Acer ACPI event GUIDs
+ */
+#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
+
 MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
 MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
+MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
+
+enum acer_wmi_event_ids {
+       WMID_HOTKEY_EVENT = 0x1,
+};
+
+static const struct key_entry acer_wmi_keymap[] = {
+       {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
+       {KE_KEY, 0x12, {KEY_BLUETOOTH} },       /* BT */
+       {KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
+       {KE_KEY, 0x22, {KEY_PROG2} },    /* Aracade */
+       {KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
+       {KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
+       {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
+       {KE_KEY, 0x82, {KEY_F22} },      /* Touch Pad On/Off */
+       {KE_END, 0}
+};
+
+static struct input_dev *acer_wmi_input_dev;
+
+struct event_return_value {
+       u8 function;
+       u8 key_num;
+       u16 device_state;
+       u32 reserved;
+} __attribute__((packed));
 
 /*
  * Interface capability flags
@@ -1085,6 +1119,99 @@ static ssize_t show_interface(struct device *dev, struct 
device_attribute *attr,
 
 static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
 
+static void acer_wmi_notify(u32 value, void *context)
+{
+       struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       struct event_return_value return_value;
+       acpi_status status;
+
+       status = wmi_get_event_data(value, &response);
+       if (status != AE_OK) {
+               printk(ACER_WARNING "bad event status 0x%x\n", status);
+               return;
+       }
+
+       obj = (union acpi_object *)response.pointer;
+
+       if (!obj)
+               return;
+       if (obj->type != ACPI_TYPE_BUFFER) {
+               printk(ACER_WARNING "Unknown response received %d\n",
+                       obj->type);
+               kfree(obj);
+               return;
+       }
+       if (obj->buffer.length != 8) {
+               printk(ACER_WARNING "Unknown buffer length %d\n",
+                       obj->buffer.length);
+               kfree(obj);
+               return;
+       }
+
+       return_value = *((struct event_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       switch (return_value.function) {
+       case WMID_HOTKEY_EVENT:
+               if (!sparse_keymap_report_event(acer_wmi_input_dev,
+                               return_value.key_num, 1, true))
+                       printk(ACER_WARNING "Unknown key number - 0x%x\n",
+                               return_value.key_num);
+               break;
+       default:
+               printk(ACER_WARNING "Unknown function number - %d - %d\n",
+                       return_value.function, return_value.key_num);
+               break;
+       }
+}
+
+static int __init acer_wmi_input_setup(void)
+{
+       acpi_status status;
+       int err;
+
+       acer_wmi_input_dev = input_allocate_device();
+       if (!acer_wmi_input_dev)
+               return -ENOMEM;
+
+       acer_wmi_input_dev->name = "Acer WMI hotkeys";
+       acer_wmi_input_dev->phys = "wmi/input0";
+       acer_wmi_input_dev->id.bustype = BUS_HOST;
+
+       err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
+       if (err)
+               goto err_free_dev;
+
+       err = input_register_device(acer_wmi_input_dev);
+       if (err)
+               goto err_free_keymap;
+
+       status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
+                                               acer_wmi_notify, NULL);
+       if (ACPI_FAILURE(status)) {
+               err = -EIO;
+               goto err_unregister_input;
+       }
+
+       return 0;
+
+err_unregister_input:
+       input_unregister_device(acer_wmi_input_dev);
+err_free_keymap:
+       sparse_keymap_free(acer_wmi_input_dev);
+err_free_dev:
+       input_free_device(acer_wmi_input_dev);
+       return err;
+}
+
+static void acer_wmi_input_destroy(void)
+{
+       wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
+       sparse_keymap_free(acer_wmi_input_dev);
+       input_unregister_device(acer_wmi_input_dev);
+}
+
 /*
  * debugfs functions
  */
@@ -1327,6 +1454,12 @@ static int __init acer_wmi_init(void)
                       "generic video driver\n");
        }
 
+       if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
+               err = acer_wmi_input_setup();
+               if (err)
+                       return err;
+       }
+
        err = platform_driver_register(&acer_platform_driver);
        if (err) {
                printk(ACER_ERR "Unable to register platform driver.\n");
@@ -1368,11 +1501,17 @@ error_device_add:
 error_device_alloc:
        platform_driver_unregister(&acer_platform_driver);
 error_platform_register:
+       if (wmi_has_guid(ACERWMID_EVENT_GUID))
+               acer_wmi_input_destroy();
+
        return err;
 }
 
 static void __exit acer_wmi_exit(void)
 {
+       if (wmi_has_guid(ACERWMID_EVENT_GUID))
+               acer_wmi_input_destroy();
+
        remove_sysfs(acer_platform_device);
        remove_debugfs();
        platform_device_unregister(acer_platform_device);
-- 
1.6.0.2

>From 1957b6b7cd071de95c0e1fb0e35cd5c9c9332630 Mon Sep 17 00:00:00 2001
From: Lee, Chun-Yi <[email protected]>
Date: Tue, 12 Oct 2010 09:27:23 +0800
Subject: [PATCH 2/2] Support enable Acer Launch Manager mode

Add a launch_manager parameter for support to enable Acer Launch Manager
mode. After enable it, the communication key will stop the default
behavior to control WLAN/Bluetooth/WWAN rfkill state. It leave usernland
application to handle the rfkill state changed.

Signed-off-by: Lee, Chun-Yi <[email protected]>
---
 drivers/platform/x86/acer-wmi.c |   74 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 74 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 32285f4..a28a775 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -85,6 +85,7 @@ MODULE_LICENSE("GPL");
 #define AMW0_GUID2             "431F16ED-0C2B-444C-B267-27DEB140CF9C"
 #define WMID_GUID1             "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
 #define WMID_GUID2             "95764E09-FB56-4e83-B31A-37761F60994A"
+#define WMID_GUID3             "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
 
 /*
  * Acer ACPI event GUIDs
@@ -120,6 +121,20 @@ struct event_return_value {
        u32 reserved;
 } __attribute__((packed));
 
+struct lm_input_params {
+       u8 function_num;        /* Function Number */
+       u16 commun_devices;     /* Communication type devices default status */
+       u16 devices;            /* Other type devices default status */
+       u8 lm_status;           /* Launch Manager Status */
+       u16 reserved;
+} __attribute__((packed));
+
+struct lm_return_value {
+       u8 error_code;          /* Error Code */
+       u8 ec_return_value;     /* EC Return Value */
+       u16 reserved;
+} __attribute__((packed));
+
 /*
  * Interface capability flags
  */
@@ -150,15 +165,18 @@ static int mailled = -1;
 static int brightness = -1;
 static int threeg = -1;
 static int force_series;
+static bool launch_manager;
 
 module_param(mailled, int, 0444);
 module_param(brightness, int, 0444);
 module_param(threeg, int, 0444);
 module_param(force_series, int, 0444);
+module_param(launch_manager, bool, 0444);
 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
 MODULE_PARM_DESC(force_series, "Force a different laptop series");
+MODULE_PARM_DESC(launch_manager, "Enable Acer Launch Manager mode");
 
 struct acer_data {
        int mailled;
@@ -1393,6 +1411,53 @@ error_debugfs:
        return -ENOMEM;
 }
 
+static int acer_wmi_enable_lm(void)
+{
+       struct lm_return_value return_value;
+       acpi_status status;
+       union acpi_object *obj;
+       struct lm_input_params params = {
+               .function_num = 0x1,
+               .commun_devices = 0x0041,       /* WiFi on, 3G on, BT off */
+               .devices = 0xFFFF,
+               .lm_status = 0x41,              /* Launch Manager Active */
+       };
+
+       struct acpi_buffer input = { sizeof(struct lm_input_params), &params };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output.pointer;
+
+       if (!obj)
+               return -EINVAL;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return -EINVAL;
+       }
+       if (obj->buffer.length != 4) {
+               printk(ACER_WARNING "Unknown buffer length %d\n",
+                       obj->buffer.length);
+               kfree(obj);
+               return -EINVAL;
+       }
+
+       return_value = *((struct lm_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value)
+               printk(ACER_WARNING "Enabling Launch Manager failed: "
+                       "0x%x - 0x%x\n", return_value.error_code,
+                       return_value.ec_return_value);
+       else
+               printk(ACER_INFO "Enabled Launch Manager");
+
+       return status;
+}
+
 static int __init acer_wmi_init(void)
 {
        int err;
@@ -1454,6 +1519,15 @@ static int __init acer_wmi_init(void)
                       "generic video driver\n");
        }
 
+       if (wmi_has_guid(WMID_GUID3) && launch_manager) {
+               if (ACPI_FAILURE(acer_wmi_enable_lm())) {
+                       printk(ACER_ERR "Cannot enable Launch Manager mode\n");
+                       return -ENODEV;
+               }
+       } else if (!wmi_has_guid(WMID_GUID3) && launch_manager) {
+               printk(ACER_INFO "No WMID launch manager enable method\n");
+       }
+
        if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
                err = acer_wmi_input_setup();
                if (err)
-- 
1.6.0.2

Reply via email to