]> err.no Git - linux-2.6/blobdiff - drivers/misc/thinkpad_acpi.c
ACPI: thinkpad-acpi: add X61t HKEY events
[linux-2.6] / drivers / misc / thinkpad_acpi.c
index dd6fa81fa8684dd627649c103716da638f5bd004..049ec42c77befc2705774ad165893470c312631d 100644 (file)
@@ -188,6 +188,7 @@ struct ibm_struct {
        int (*write) (char *);
        void (*exit) (void);
        void (*resume) (void);
+       void (*suspend) (pm_message_t state);
 
        struct list_head all_drivers;
 
@@ -658,6 +659,21 @@ static struct input_dev *tpacpi_inputdev;
 static struct mutex tpacpi_inputdev_send_mutex;
 static LIST_HEAD(tpacpi_all_drivers);
 
+static int tpacpi_suspend_handler(struct platform_device *pdev,
+                                 pm_message_t state)
+{
+       struct ibm_struct *ibm, *itmp;
+
+       list_for_each_entry_safe(ibm, itmp,
+                                &tpacpi_all_drivers,
+                                all_drivers) {
+               if (ibm->suspend)
+                       (ibm->suspend)(state);
+       }
+
+       return 0;
+}
+
 static int tpacpi_resume_handler(struct platform_device *pdev)
 {
        struct ibm_struct *ibm, *itmp;
@@ -677,6 +693,7 @@ static struct platform_driver tpacpi_pdriver = {
                .name = TPACPI_DRVR_NAME,
                .owner = THIS_MODULE,
        },
+       .suspend = tpacpi_suspend_handler,
        .resume = tpacpi_resume_handler,
 };
 
@@ -1001,6 +1018,14 @@ static unsigned int hotkey_config_change;
 
 static struct mutex hotkey_mutex;
 
+static enum {  /* Reasons for waking up */
+       TP_ACPI_WAKEUP_NONE = 0,        /* None or unknown */
+       TP_ACPI_WAKEUP_BAYEJ,           /* Bay ejection request */
+       TP_ACPI_WAKEUP_UNDOCK,          /* Undock request */
+} hotkey_wakeup_reason;
+
+static int hotkey_autosleep_ack;
+
 static int hotkey_orig_status;
 static u32 hotkey_orig_mask;
 static u32 hotkey_all_mask;
@@ -1644,6 +1669,29 @@ static ssize_t hotkey_report_mode_show(struct device *dev,
 static struct device_attribute dev_attr_hotkey_report_mode =
        __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
 
+/* sysfs wakeup reason ------------------------------------------------- */
+static ssize_t hotkey_wakeup_reason_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason);
+}
+
+static struct device_attribute dev_attr_hotkey_wakeup_reason =
+       __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL);
+
+/* sysfs wakeup hotunplug_complete ------------------------------------- */
+static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack);
+}
+
+static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete =
+       __ATTR(wakeup_hotunplug_complete, S_IRUGO,
+              hotkey_wakeup_hotunplug_complete_show, NULL);
+
 /* --------------------------------------------------------------------- */
 
 static struct attribute *hotkey_attributes[] __initdata = {
@@ -1666,6 +1714,8 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
        &dev_attr_hotkey_all_mask.attr,
        &dev_attr_hotkey_recommended_mask.attr,
 #endif
+       &dev_attr_hotkey_wakeup_reason.attr,
+       &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
 };
 
 static int __init hotkey_init(struct ibm_init_struct *iibm)
@@ -1805,7 +1855,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                str_supported(tp_features.hotkey));
 
        if (tp_features.hotkey) {
-               hotkey_dev_attributes = create_attr_set(10, NULL);
+               hotkey_dev_attributes = create_attr_set(12, NULL);
                if (!hotkey_dev_attributes)
                        return -ENOMEM;
                res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1990,6 +2040,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
        unsigned int scancode;
        int send_acpi_ev;
        int ignore_acpi_ev;
+       int unk_ev;
 
        if (event != 0x80) {
                printk(TPACPI_ERR
@@ -2013,8 +2064,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        return;
                }
 
-               send_acpi_ev = 0;
+               send_acpi_ev = 1;
                ignore_acpi_ev = 0;
+               unk_ev = 0;
 
                switch (hkey >> 12) {
                case 1:
@@ -2024,46 +2076,88 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                                scancode--;
                                if (!(hotkey_source_mask & (1 << scancode))) {
                                        tpacpi_input_send_key(scancode);
+                                       send_acpi_ev = 0;
                                } else {
                                        ignore_acpi_ev = 1;
                                }
                        } else {
-                               printk(TPACPI_ERR
-                                      "hotkey 0x%04x out of range "
-                                      "for keyboard map\n", hkey);
-                               send_acpi_ev = 1;
+                               unk_ev = 1;
                        }
                        break;
-               case 5:
-                       /* 0x5000-0x5FFF: LID */
-                       /* we don't handle it through this path, just
-                        * eat up known LID events */
-                       if (hkey != 0x5001 && hkey != 0x5002) {
-                               printk(TPACPI_ERR
-                                      "unknown LID-related HKEY event: "
-                                      "0x%04x\n", hkey);
-                               send_acpi_ev = 1;
+               case 2:
+                       /* Wakeup reason */
+                       switch (hkey) {
+                       case 0x2304: /* suspend, undock */
+                       case 0x2404: /* hibernation, undock */
+                               hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
+                               ignore_acpi_ev = 1;
+                               break;
+                       case 0x2305: /* suspend, bay eject */
+                       case 0x2405: /* hibernation, bay eject */
+                               hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
+                               ignore_acpi_ev = 1;
+                               break;
+                       default:
+                               unk_ev = 1;
+                       }
+                       if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
+                               printk(TPACPI_INFO
+                                      "woke up due to a hot-unplug "
+                                      "request...\n");
+                       }
+                       break;
+               case 3:
+                       /* bay-related wakeups */
+                       if (hkey == 0x3003) {
+                               hotkey_autosleep_ack = 1;
+                               printk(TPACPI_INFO
+                                      "bay ejected\n");
                        } else {
+                               unk_ev = 1;
+                       }
+                       break;
+               case 4:
+                       /* dock-related wakeups */
+                       if (hkey == 0x4003) {
+                               hotkey_autosleep_ack = 1;
+                               printk(TPACPI_INFO
+                                      "undocked\n");
+                       } else {
+                               unk_ev = 1;
+                       }
+                       break;
+               case 5:
+                       /* 0x5000-0x5FFF: human interface helpers */
+                       switch (hkey) {
+                       case 0x5010: /* Lenovo new BIOS: brightness changed */
+                       case 0x5009: /* X61t: swivel up (tablet mode) */
+                       case 0x500a: /* X61t: swivel down (normal mode) */
+                       case 0x500b: /* X61t: tablet pen inserted into bay */
+                       case 0x500c: /* X61t: tablet pen removed from bay */
+                               break;
+                       case 0x5001:
+                       case 0x5002:
+                               /* LID switch events.  Do not propagate */
                                ignore_acpi_ev = 1;
+                               break;
+                       default:
+                               unk_ev = 1;
                        }
                        break;
                case 7:
                        /* 0x7000-0x7FFF: misc */
                        if (tp_features.hotkey_wlsw && hkey == 0x7000) {
                                tpacpi_input_send_radiosw();
+                               send_acpi_ev = 0;
                                break;
                        }
                        /* fallthrough to default */
                default:
-                       /* case 2: dock-related */
-                       /*      0x2305 - T43 waking up due to bay lever
-                        *               eject while aslept */
-                       /* case 3: ultra-bay related. maybe bay in dock? */
-                       /*      0x3003 - T43 after wake up by bay lever
-                        *               eject (0x2305) */
+                       unk_ev = 1;
+               }
+               if (unk_ev) {
                        printk(TPACPI_NOTICE
                               "unhandled HKEY event 0x%04x\n", hkey);
-                       send_acpi_ev = 1;
                }
 
                /* Legacy events */
@@ -2083,6 +2177,13 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
        }
 }
 
+static void hotkey_suspend(pm_message_t state)
+{
+       /* Do these on suspend, we get the events on early resume! */
+       hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
+       hotkey_autosleep_ack = 0;
+}
+
 static void hotkey_resume(void)
 {
        if (hotkey_mask_get())
@@ -2190,6 +2291,7 @@ static struct ibm_struct hotkey_driver_data = {
        .write = hotkey_write,
        .exit = hotkey_exit,
        .resume = hotkey_resume,
+       .suspend = hotkey_suspend,
        .acpi = &ibm_hotkey_acpidriver,
 };