Merge branches 'release', 'bugzilla-9916', 'bugzilla-9982', 'bugzilla-9989', 'misc...
authorLen Brown <len.brown@intel.com>
Thu, 21 Feb 2008 07:41:58 +0000 (02:41 -0500)
committerLen Brown <len.brown@intel.com>
Thu, 21 Feb 2008 07:41:58 +0000 (02:41 -0500)
14 files changed:
Documentation/laptops/thinkpad-acpi.txt
drivers/acpi/ec.c
drivers/acpi/executer/exregion.c
drivers/acpi/fan.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/utils.c
drivers/acpi/video.c
drivers/misc/Kconfig
drivers/misc/acer-wmi.c
drivers/misc/intel_menlow.c
drivers/misc/thinkpad_acpi.c
drivers/pci/pci-acpi.c
drivers/thermal/thermal.c

index 6c2477754a2a35025e8c837740693275d2df8f21..76cb428435daf4c1dfe9d611fd6a155483e447a2 100644 (file)
@@ -160,7 +160,7 @@ Hot keys
 procfs: /proc/acpi/ibm/hotkey
 sysfs device attribute: hotkey_*
 
-In a ThinkPad, the ACPI HKEY handler is responsible for comunicating
+In a ThinkPad, the ACPI HKEY handler is responsible for communicating
 some important events and also keyboard hot key presses to the operating
 system.  Enabling the hotkey functionality of thinkpad-acpi signals the
 firmware that such a driver is present, and modifies how the ThinkPad
@@ -193,7 +193,7 @@ Not all bits in the mask can be modified.  Not all bits that can be
 modified do anything.  Not all hot keys can be individually controlled
 by the mask.  Some models do not support the mask at all, and in those
 models, hot keys cannot be controlled individually.  The behaviour of
-the mask is, therefore, higly dependent on the ThinkPad model.
+the mask is, therefore, highly dependent on the ThinkPad model.
 
 Note that unmasking some keys prevents their default behavior.  For
 example, if Fn+F5 is unmasked, that key will no longer enable/disable
@@ -288,7 +288,7 @@ sysfs notes:
                in ACPI event mode, volume up/down/mute are reported as
                separate events, but this behaviour may be corrected in
                future releases of this driver, in which case the
-               ThinkPad volume mixer user interface semanthics will be
+               ThinkPad volume mixer user interface semantics will be
                enforced.
 
        hotkey_poll_freq:
@@ -306,13 +306,20 @@ sysfs notes:
                The recommended polling frequency is 10Hz.
 
        hotkey_radio_sw:
-               if the ThinkPad has a hardware radio switch, this
+               If the ThinkPad has a hardware radio switch, this
                attribute will read 0 if the switch is in the "radios
-               disabled" postition, and 1 if the switch is in the
+               disabled" position, and 1 if the switch is in the
                "radios enabled" position.
 
                This attribute has poll()/select() support.
 
+       hotkey_tablet_mode:
+               If the ThinkPad has tablet capabilities, this attribute
+               will read 0 if the ThinkPad is in normal mode, and
+               1 if the ThinkPad is in tablet mode.
+
+               This attribute has poll()/select() support.
+
        hotkey_report_mode:
                Returns the state of the procfs ACPI event report mode
                filter for hot keys.  If it is set to 1 (the default),
@@ -339,7 +346,7 @@ sysfs notes:
        wakeup_hotunplug_complete:
                Set to 1 if the system was waken up because of an
                undock or bay ejection request, and that request
-               was sucessfully completed.  At this point, it might
+               was successfully completed.  At this point, it might
                be useful to send the system back to sleep, at the
                user's choice.  Refer to HKEY events 0x4003 and
                0x3003, below.
@@ -392,7 +399,7 @@ event       code    Key             Notes
                                Lenovo: battery
 
 0x1004 0x03    FN+F4           Sleep button (ACPI sleep button
-                               semanthics, i.e. sleep-to-RAM).
+                               semantics, i.e. sleep-to-RAM).
                                It is always generate some kind
                                of event, either the hot key
                                event or a ACPI sleep button
@@ -403,12 +410,12 @@ event     code    Key             Notes
                                time passes.
 
 0x1005 0x04    FN+F5           Radio.  Enables/disables
-                               the internal BlueTooth hardware
+                               the internal Bluetooth hardware
                                and W-WAN card if left in control
                                of the firmware.  Does not affect
                                the WLAN card.
                                Should be used to turn on/off all
-                               radios (bluetooth+W-WAN+WLAN),
+                               radios (Bluetooth+W-WAN+WLAN),
                                really.
 
 0x1006 0x05    FN+F6           -
@@ -417,7 +424,7 @@ event       code    Key             Notes
                                Do you feel lucky today?
 
 0x1008 0x07    FN+F8           IBM: toggle screen expand
-                               Lenovo: configure ultranav
+                               Lenovo: configure UltraNav
 
 0x1009 0x08    FN+F9           -
        ..      ..              ..
@@ -447,7 +454,7 @@ event       code    Key             Notes
 0x1011 0x10    FN+END          Brightness down.  See brightness
                                up for details.
 
-0x1012 0x11    FN+PGUP         Thinklight toggle.  This key is
+0x1012 0x11    FN+PGUP         ThinkLight toggle.  This key is
                                always handled by the firmware,
                                even when unmasked.
 
@@ -469,7 +476,7 @@ event       code    Key             Notes
                                key is always handled by the
                                firmware, even when unmasked.
 
-0x1018 0x17    THINKPAD        Thinkpad/Access IBM/Lenovo key
+0x1018 0x17    THINKPAD        ThinkPad/Access IBM/Lenovo key
 
 0x1019 0x18    unknown
 ..     ..      ..
@@ -488,9 +495,17 @@ If a key is mapped to KEY_UNKNOWN, it generates an input event that
 includes an scan code.  If a key is mapped to anything else, it will
 generate input device EV_KEY events.
 
+In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW
+events for switches:
+
+SW_RADIO       T60 and later hardare rfkill rocker switch
+SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A
+
 Non hot-key ACPI HKEY event map:
 0x5001         Lid closed
 0x5002         Lid opened
+0x5009         Tablet swivel: switched to tablet mode
+0x500A         Tablet swivel: switched to normal mode
 0x7000         Radio Switch may have changed state
 
 The above events are not propagated by the driver, except for legacy
@@ -505,9 +520,7 @@ The above events are never propagated by the driver.
 
 0x3003         Bay ejection (see 0x2x05) complete, can sleep again
 0x4003         Undocked (see 0x2x04), can sleep again
-0x5009         Tablet swivel: switched to tablet mode
-0x500A         Tablet swivel: switched to normal mode
-0x500B         Tablet pen insterted into its storage bay
+0x500B         Tablet pen inserted into its storage bay
 0x500C         Tablet pen removed from its storage bay
 0x5010         Brightness level changed (newer Lenovo BIOSes)
 
@@ -539,7 +552,7 @@ sysfs (it is read-only).
 If the hotkey_report_mode module parameter is set to 1 or 2, it cannot
 be changed later through sysfs (any writes will return -EPERM to signal
 that hotkey_report_mode was locked.  On 2.6.23 and later, where
-hotkey_report_mode cannot be changed at all, writes will return -EACES).
+hotkey_report_mode cannot be changed at all, writes will return -EACCES).
 
 hotkey_report_mode set to 1 makes the driver export through the procfs
 ACPI event interface all hot key presses (which are *also* sent to the
@@ -584,7 +597,7 @@ Sysfs notes:
                0: disables Bluetooth / Bluetooth is disabled
                1: enables Bluetooth / Bluetooth is enabled.
 
-       Note: this interface will be probably be superseeded by the
+       Note: this interface will be probably be superseded by the
        generic rfkill class, so it is NOT to be considered stable yet.
 
 Video output control -- /proc/acpi/ibm/video
@@ -791,12 +804,12 @@ on the X40 (tpb is the ThinkPad Buttons utility):
        1 - Related to "Volume up" key press
        2 - Related to "Mute on" key press
        3 - Related to "Access IBM" key press
-       4 - Related to "LCD brightness up" key pess
+       4 - Related to "LCD brightness up" key press
        5 - Related to "LCD brightness down" key press
        11 - Related to "toggle screen expansion" key press/function
        12 - Related to "ThinkLight on"
        13 - Related to "ThinkLight off"
-       14 - Related to "ThinkLight" key press (toggle thinklight)
+       14 - Related to "ThinkLight" key press (toggle ThinkLight)
 
 The cmos command interface is prone to firmware split-brain problems, as
 in newer ThinkPads it is just a compatibility layer.  Do not use it, it is
@@ -1024,7 +1037,7 @@ There are two interfaces to the firmware for direct brightness control,
 EC and CMOS.  To select which one should be used, use the
 brightness_mode module parameter: brightness_mode=1 selects EC mode,
 brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC
-and CMOS.  The driver tries to autodetect which interface to use.
+and CMOS.  The driver tries to auto-detect which interface to use.
 
 When display backlight brightness controls are available through the
 standard ACPI interface, it is best to use it instead of this direct
@@ -1266,8 +1279,8 @@ experimental=1 parameter when loading the module.
 This feature shows the presence and current state of a W-WAN (Sierra
 Wireless EV-DO) device.
 
-It was tested on a Lenovo Thinkpad X60. It should probably work on other
-Thinkpad models which come with this module installed.
+It was tested on a Lenovo ThinkPad X60. It should probably work on other
+ThinkPad models which come with this module installed.
 
 Procfs notes:
 
@@ -1286,7 +1299,7 @@ Sysfs notes:
                0: disables WWAN card / WWAN card is disabled
                1: enables WWAN card / WWAN card is enabled.
 
-       Note: this interface will be probably be superseeded by the
+       Note: this interface will be probably be superseded by the
        generic rfkill class, so it is NOT to be considered stable yet.
 
 Multiple Commands, Module Parameters
@@ -1309,7 +1322,7 @@ Enabling debugging output
 The module takes a debug parameter which can be used to selectively
 enable various classes of debugging output, for example:
 
-        modprobe ibm_acpi debug=0xffff
+        modprobe thinkpad_acpi debug=0xffff
 
 will enable all debugging output classes.  It takes a bitmask, so
 to enable more than one output class, just add their values.
@@ -1356,7 +1369,7 @@ Sysfs interface changelog:
                NVRAM is compiled out by the user because it is
                unneeded/undesired in the first place).
 0x020101:      Marker for thinkpad-acpi with hot key NVRAM polling
-               and proper hotkey_mask semanthics (version 8 of the
+               and proper hotkey_mask semantics (version 8 of the
                NVRAM polling patch).  Some development snapshots of
                0.18 had an earlier version that did strange things
                to hotkey_mask.
index 7222a18a03198d0bc70121d1246dc27af1d0629e..caf873c14bfb244a89ba9c322ada05c3c2b3c04e 100644 (file)
@@ -943,7 +943,11 @@ int __init acpi_ec_ecdt_probe(void)
                boot_ec->command_addr = ecdt_ptr->control.address;
                boot_ec->data_addr = ecdt_ptr->data.address;
                boot_ec->gpe = ecdt_ptr->gpe;
-               boot_ec->handle = ACPI_ROOT_OBJECT;
+               if (ACPI_FAILURE(acpi_get_handle(NULL, ecdt_ptr->id,
+                               &boot_ec->handle))) {
+                       pr_info("Failed to locate handle for boot EC\n");
+                       boot_ec->handle = ACPI_ROOT_OBJECT;
+               }
        } else {
                /* This workaround is needed only on some broken machines,
                 * which require early EC, but fail to provide ECDT */
index 2e9ce94798c7dbb59fd628f493bb0970cde6ed85..3f51b7e84a17f532801dd47bdff391f5252bcc55 100644 (file)
@@ -338,6 +338,7 @@ acpi_ex_pci_config_space_handler(u32 function,
        acpi_status status = AE_OK;
        struct acpi_pci_id *pci_id;
        u16 pci_register;
+       u32 value32;
 
        ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
 
@@ -364,9 +365,9 @@ acpi_ex_pci_config_space_handler(u32 function,
        switch (function) {
        case ACPI_READ:
 
-               *value = 0;
                status = acpi_os_read_pci_configuration(pci_id, pci_register,
-                                                       value, bit_width);
+                                                       &value32, bit_width);
+               *value = value32;
                break;
 
        case ACPI_WRITE:
index 48cb705b274afb837129ae6d13ead27f8f2c6ccc..c8e3cba423ef19d7548b63bfdb041d266454d4e1 100644 (file)
@@ -256,22 +256,28 @@ static int acpi_fan_add(struct acpi_device *device)
 
        cdev = thermal_cooling_device_register("Fan", device,
                                                &fan_cooling_ops);
-       if (cdev)
+       if (IS_ERR(cdev)) {
+               result = PTR_ERR(cdev);
+               goto end;
+       }
+       if (cdev) {
                printk(KERN_INFO PREFIX
                        "%s is registered as cooling_device%d\n",
                        device->dev.bus_id, cdev->id);
-       else
-               goto end;
-       acpi_driver_data(device) = cdev;
-       result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj,
-                                       "thermal_cooling");
-       if (result)
-               return result;
 
-       result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj,
-                                       "device");
-        if (result)
-                return result;
+               acpi_driver_data(device) = cdev;
+               result = sysfs_create_link(&device->dev.kobj,
+                                          &cdev->device.kobj,
+                                          "thermal_cooling");
+               if (result)
+                       return result;
+
+               result = sysfs_create_link(&cdev->device.kobj,
+                                          &device->dev.kobj,
+                                          "device");
+               if (result)
+                       return result;
+       }
 
        result = acpi_fan_add_fs(device);
        if (result)
index 75ccf5d18bf4e3630e892dd0021a8c890a0fc0c2..a3cc8a98255cf724248c7efbf749a912bc9ef4f1 100644 (file)
@@ -670,21 +670,26 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
 
        pr->cdev = thermal_cooling_device_register("Processor", device,
                                                &processor_cooling_ops);
-       if (pr->cdev)
+       if (IS_ERR(pr->cdev)) {
+               result = PTR_ERR(pr->cdev);
+               goto end;
+       }
+       if (pr->cdev) {
                printk(KERN_INFO PREFIX
                        "%s is registered as cooling_device%d\n",
                        device->dev.bus_id, pr->cdev->id);
-       else
-               goto end;
 
-       result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj,
-                                       "thermal_cooling");
-       if (result)
-               return result;
-       result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj,
-                                       "device");
-       if (result)
-               return result;
+               result = sysfs_create_link(&device->dev.kobj,
+                                          &pr->cdev->device.kobj,
+                                          "thermal_cooling");
+               if (result)
+                       return result;
+               result = sysfs_create_link(&pr->cdev->device.kobj,
+                                          &device->dev.kobj,
+                                          "device");
+               if (result)
+                       return result;
+       }
 
        if (pr->flags.throttling) {
                printk(KERN_INFO PREFIX "%s [%s] (supports",
@@ -809,10 +814,12 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
 
        acpi_processor_remove_fs(device);
 
-       sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
-       sysfs_remove_link(&pr->cdev->device.kobj, "device");
-       thermal_cooling_device_unregister(pr->cdev);
-       pr->cdev = NULL;
+       if (pr->cdev) {
+               sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+               sysfs_remove_link(&pr->cdev->device.kobj, "device");
+               thermal_cooling_device_unregister(pr->cdev);
+               pr->cdev = NULL;
+       }
 
        processors[pr->id] = NULL;
 
@@ -826,8 +833,6 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
  *     Acpi processor hotplug support                                      *
  ****************************************************************************/
 
-static int is_processor_present(acpi_handle handle);
-
 static int is_processor_present(acpi_handle handle)
 {
        acpi_status status;
index 980e1c33e6c5eeb11a7ec91132c2aa1cb614ef0a..6f3b217699e94a4d47f5b3863c4ffe68ff24938f 100644 (file)
@@ -364,7 +364,7 @@ int acpi_processor_resume(struct acpi_device * device)
        return 0;
 }
 
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
 static int tsc_halts_in_c(int state)
 {
        switch (boot_cpu_data.x86_vendor) {
@@ -544,7 +544,7 @@ static void acpi_processor_idle(void)
                /* Get end time (ticks) */
                t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
                /* TSC halts in C2, so notify users */
                if (tsc_halts_in_c(ACPI_STATE_C2))
                        mark_tsc_unstable("possible TSC halt in C2");
@@ -609,7 +609,7 @@ static void acpi_processor_idle(void)
                        acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
                }
 
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
                /* TSC halts in C3, so notify users */
                if (tsc_halts_in_c(ACPI_STATE_C3))
                        mark_tsc_unstable("TSC halts in C3");
@@ -1500,7 +1500,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        acpi_idle_do_entry(cx);
        t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
        /* TSC could halt in idle, so notify users */
        if (tsc_halts_in_c(cx->type))
                mark_tsc_unstable("TSC halts in idle");;
@@ -1614,7 +1614,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                spin_unlock(&c3_lock);
        }
 
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
        /* TSC could halt in idle, so notify users */
        if (tsc_halts_in_c(ACPI_STATE_C3))
                mark_tsc_unstable("TSC halts in idle");
index 34f1575710807eada4cfd4ff8162b9753b4cfd1b..eba55b7d6c95ad63479430fc3c63c57dce3a5b19 100644 (file)
@@ -36,16 +36,20 @@ ACPI_MODULE_NAME("utils");
 /* --------------------------------------------------------------------------
                             Object Evaluation Helpers
    -------------------------------------------------------------------------- */
+static void
+acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
+{
 #ifdef ACPI_DEBUG_OUTPUT
-#define acpi_util_eval_error(h,p,s) {\
-       char prefix[80] = {'\0'};\
-       struct acpi_buffer buffer = {sizeof(prefix), prefix};\
-       acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",\
-               (char *) prefix, p, acpi_format_exception(s))); }
+       char prefix[80] = {'\0'};
+       struct acpi_buffer buffer = {sizeof(prefix), prefix};
+       acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
+               (char *) prefix, p, acpi_format_exception(s)));
 #else
-#define acpi_util_eval_error(h,p,s)
+       return;
 #endif
+}
+
 acpi_status
 acpi_extract_package(union acpi_object *package,
                     struct acpi_buffer *format, struct acpi_buffer *buffer)
index 7f714fa2a4547d284323d85441e60a9c6b61600f..12cce69b5441e98a7bd8da23031dc250daaa88f1 100644 (file)
@@ -731,6 +731,9 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 
                device->cdev = thermal_cooling_device_register("LCD",
                                        device->dev, &video_cooling_ops);
+               if (IS_ERR(device->cdev))
+                       return;
+
                if (device->cdev) {
                        printk(KERN_INFO PREFIX
                                "%s is registered as cooling_device%d\n",
index 1abc95ca9dfa2fe67aaa85405b259d16427c639c..982e27b86d101a15ebb2f579652a67d4ae08f806 100644 (file)
@@ -258,6 +258,23 @@ config THINKPAD_ACPI_BAY
 
          If you are not sure, say Y here.
 
+config THINKPAD_ACPI_VIDEO
+       bool "Video output control support"
+       depends on THINKPAD_ACPI
+       default y
+       ---help---
+         Allows the thinkpad_acpi driver to provide an interface to control
+         the various video output ports.
+
+         This feature often won't work well, depending on ThinkPad model,
+         display state, video output devices in use, whether there is a X
+         server running, phase of the moon, and the current mood of
+         Schroedinger's cat.  If you can use X.org's RandR to control
+         your ThinkPad's video output ports instead of this feature,
+         don't think twice: do it and say N here to save some memory.
+
+         If you are not sure, say Y here.
+
 config THINKPAD_ACPI_HOTKEY_POLL
        bool "Suport NVRAM polling for hot keys"
        depends on THINKPAD_ACPI
index d7aea93081f26f98310ebbb1db6a4e29e1ed7ffb..74d12b4a3abdae48be072857ec75a34c90496dcb 100644 (file)
@@ -271,6 +271,15 @@ static struct dmi_system_id acer_quirks[] = {
                },
                .driver_data = &quirk_acer_travelmate_2490,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Acer TravelMate 4200",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
+               },
+               .driver_data = &quirk_acer_travelmate_2490,
+       },
        {
                .callback = dmi_matched,
                .ident = "Medion MD 98300",
index f70984ab1e1bdfd2c1aa25a32108f6b96117f83b..de16e88eb8d3d89785fdefce12a7953c878bb0c6 100644 (file)
@@ -170,10 +170,13 @@ static int intel_menlow_memory_add(struct acpi_device *device)
 
        cdev = thermal_cooling_device_register("Memory controller", device,
                                               &memory_cooling_ops);
-       acpi_driver_data(device) = cdev;
-       if (!cdev)
-               result = -ENODEV;
-       else {
+       if (IS_ERR(cdev)) {
+               result = PTR_ERR(cdev);
+               goto end;
+       }
+
+       if (cdev) {
+               acpi_driver_data(device) = cdev;
                result = sysfs_create_link(&device->dev.kobj,
                                        &cdev->device.kobj, "thermal_cooling");
                if (result)
index e2c7edd206a6b0677894ec6bddfd779cd0851543..bb269d0c677edbc4cadd268dc634e90b6120a80e 100644 (file)
@@ -221,6 +221,7 @@ static struct {
        u32 hotkey:1;
        u32 hotkey_mask:1;
        u32 hotkey_wlsw:1;
+       u32 hotkey_tablet:1;
        u32 light:1;
        u32 light_status:1;
        u32 bright_16levels:1;
@@ -301,6 +302,13 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY",      /* 600e/x, 770e, 770x */
           "HKEY",              /* all others */
           );                   /* 570 */
 
+TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",  /* 570 */
+          "\\_SB.PCI0.AGP0.VID0",      /* 600e/x, 770x */
+          "\\_SB.PCI0.VID0",   /* 770e */
+          "\\_SB.PCI0.VID",    /* A21e, G4x, R50e, X30, X40 */
+          "\\_SB.PCI0.AGP.VID",        /* all others */
+          );                           /* R30, R31 */
+
 
 /*************************************************************************
  * ACPI helpers
@@ -1053,6 +1061,9 @@ static struct attribute_set *hotkey_dev_attributes;
 #define HOTKEY_CONFIG_CRITICAL_END
 #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
 
+/* HKEY.MHKG() return bits */
+#define TP_HOTKEY_TABLET_MASK (1 << 3)
+
 static int hotkey_get_wlsw(int *status)
 {
        if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -1060,6 +1071,16 @@ static int hotkey_get_wlsw(int *status)
        return 0;
 }
 
+static int hotkey_get_tablet_mode(int *status)
+{
+       int s;
+
+       if (!acpi_evalf(hkey_handle, &s, "MHKG", "d"))
+               return -EIO;
+
+       return ((s & TP_HOTKEY_TABLET_MASK) != 0);
+}
+
 /*
  * Call with hotkey_mutex held
  */
@@ -1154,15 +1175,31 @@ static void tpacpi_input_send_radiosw(void)
 {
        int wlsw;
 
-       mutex_lock(&tpacpi_inputdev_send_mutex);
-
        if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
+               mutex_lock(&tpacpi_inputdev_send_mutex);
+
                input_report_switch(tpacpi_inputdev,
                                    SW_RADIO, !!wlsw);
                input_sync(tpacpi_inputdev);
+
+               mutex_unlock(&tpacpi_inputdev_send_mutex);
        }
+}
+
+static void tpacpi_input_send_tabletsw(void)
+{
+       int state;
+
+       if (tp_features.hotkey_tablet &&
+           !hotkey_get_tablet_mode(&state)) {
+               mutex_lock(&tpacpi_inputdev_send_mutex);
 
-       mutex_unlock(&tpacpi_inputdev_send_mutex);
+               input_report_switch(tpacpi_inputdev,
+                                   SW_TABLET_MODE, !!state);
+               input_sync(tpacpi_inputdev);
+
+               mutex_unlock(&tpacpi_inputdev_send_mutex);
+       }
 }
 
 static void tpacpi_input_send_key(unsigned int scancode)
@@ -1417,6 +1454,14 @@ static void hotkey_poll_setup_safe(int may_warn)
        mutex_unlock(&hotkey_mutex);
 }
 
+#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+static void hotkey_poll_setup_safe(int __unused)
+{
+}
+
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
 static int hotkey_inputdev_open(struct input_dev *dev)
 {
        switch (tpacpi_lifecycle) {
@@ -1444,7 +1489,6 @@ static void hotkey_inputdev_close(struct input_dev *dev)
        if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
                hotkey_poll_setup_safe(0);
 }
-#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
 
 /* sysfs hotkey enable ------------------------------------------------- */
 static ssize_t hotkey_enable_show(struct device *dev,
@@ -1666,6 +1710,29 @@ static void hotkey_radio_sw_notify_change(void)
                             "hotkey_radio_sw");
 }
 
+/* sysfs hotkey tablet mode (pollable) --------------------------------- */
+static ssize_t hotkey_tablet_mode_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       int res, s;
+       res = hotkey_get_tablet_mode(&s);
+       if (res < 0)
+               return res;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_tablet_mode =
+       __ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL);
+
+static void hotkey_tablet_mode_notify_change(void)
+{
+       if (tp_features.hotkey_tablet)
+               sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+                            "hotkey_tablet_mode");
+}
+
 /* sysfs hotkey report_mode -------------------------------------------- */
 static ssize_t hotkey_report_mode_show(struct device *dev,
                           struct device_attribute *attr,
@@ -1878,7 +1945,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(12, NULL);
+               hotkey_dev_attributes = create_attr_set(13, NULL);
                if (!hotkey_dev_attributes)
                        return -ENOMEM;
                res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1957,6 +2024,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                                        &dev_attr_hotkey_radio_sw.attr);
                }
 
+               /* For X41t, X60t, X61t Tablets... */
+               if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
+                       tp_features.hotkey_tablet = 1;
+                       printk(TPACPI_INFO
+                               "possible tablet mode switch found; "
+                               "ThinkPad in %s mode\n",
+                               (status & TP_HOTKEY_TABLET_MASK)?
+                                       "tablet" : "laptop");
+                       res = add_to_attr_set(hotkey_dev_attributes,
+                                       &dev_attr_hotkey_tablet_mode.attr);
+               }
+
                if (!res)
                        res = register_attr_set_with_sysfs(
                                        hotkey_dev_attributes,
@@ -2006,6 +2085,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                        set_bit(EV_SW, tpacpi_inputdev->evbit);
                        set_bit(SW_RADIO, tpacpi_inputdev->swbit);
                }
+               if (tp_features.hotkey_tablet) {
+                       set_bit(EV_SW, tpacpi_inputdev->evbit);
+                       set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
+               }
 
                dbg_printk(TPACPI_DBG_INIT,
                                "enabling hot key handling\n");
@@ -2023,12 +2106,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                                (hotkey_report_mode < 2) ?
                                        "enabled" : "disabled");
 
-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
                tpacpi_inputdev->open = &hotkey_inputdev_open;
                tpacpi_inputdev->close = &hotkey_inputdev_close;
 
                hotkey_poll_setup_safe(1);
-#endif
+               tpacpi_input_send_radiosw();
+               tpacpi_input_send_tabletsw();
        }
 
        return (tp_features.hotkey)? 0 : 1;
@@ -2156,11 +2239,15 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        /* 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 0x5009: /* X41t-X61t: swivel up (tablet mode) */
+                       case 0x500a: /* X41t-X61t: swivel down (normal mode) */
+                               tpacpi_input_send_tabletsw();
+                               hotkey_tablet_mode_notify_change();
+                               send_acpi_ev = 0;
+                               break;
                        case 0x5001:
                        case 0x5002:
                                /* LID switch events.  Do not propagate */
@@ -2219,11 +2306,10 @@ static void hotkey_resume(void)
                       "from firmware\n");
        tpacpi_input_send_radiosw();
        hotkey_radio_sw_notify_change();
+       hotkey_tablet_mode_notify_change();
        hotkey_wakeup_reason_notify_change();
        hotkey_wakeup_hotunplug_complete_notify_change();
-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
        hotkey_poll_setup_safe(0);
-#endif
 }
 
 /* procfs -------------------------------------------------------------- */
@@ -2676,6 +2762,8 @@ static struct ibm_struct wan_driver_data = {
  * Video subdriver
  */
 
+#ifdef CONFIG_THINKPAD_ACPI_VIDEO
+
 enum video_access_mode {
        TPACPI_VIDEO_NONE = 0,
        TPACPI_VIDEO_570,       /* 570 */
@@ -2703,13 +2791,6 @@ static int video_orig_autosw;
 static int video_autosw_get(void);
 static int video_autosw_set(int enable);
 
-TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",  /* 570 */
-          "\\_SB.PCI0.AGP0.VID0",      /* 600e/x, 770x */
-          "\\_SB.PCI0.VID0",   /* 770e */
-          "\\_SB.PCI0.VID",    /* A21e, G4x, R50e, X30, X40 */
-          "\\_SB.PCI0.AGP.VID",        /* all others */
-          );                           /* R30, R31 */
-
 TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID");      /* G41 */
 
 static int __init video_init(struct ibm_init_struct *iibm)
@@ -3019,6 +3100,8 @@ static struct ibm_struct video_driver_data = {
        .exit = video_exit,
 };
 
+#endif /* CONFIG_THINKPAD_ACPI_VIDEO */
+
 /*************************************************************************
  * Light (thinklight) subdriver
  */
@@ -5803,10 +5886,12 @@ static struct ibm_init_struct ibms_init[] __initdata = {
                .init = wan_init,
                .data = &wan_driver_data,
        },
+#ifdef CONFIG_THINKPAD_ACPI_VIDEO
        {
                .init = video_init,
                .data = &video_driver_data,
        },
+#endif
        {
                .init = light_init,
                .data = &light_driver_data,
@@ -5918,7 +6003,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
 
 #define TPACPI_PARAM(feature) \
        module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
-       MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \
+       MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \
                         "at module load, see documentation")
 
 TPACPI_PARAM(hotkey);
index e818e52dc39ab373e164feec754200f0eac0d1e7..4a23654184fc04da02eb1a73468818709fbe6371 100644 (file)
@@ -158,6 +158,7 @@ run_osc_out:
 /**
  * __pci_osc_support_set - register OS support to Firmware
  * @flags: OS support bits
+ * @hid: hardware ID
  *
  * Update OS support fields and doing a _OSC Query to obtain an update
  * from Firmware on supported control bits.
index e782b3e7fcdb01c8b525e845e565538143bd2012..8b86e53ccf7a081586d32d09350dce072f2ef75e 100644 (file)
@@ -306,12 +306,23 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
 {
        struct thermal_cooling_device_instance *dev;
        struct thermal_cooling_device_instance *pos;
+       struct thermal_zone_device *pos1;
+       struct thermal_cooling_device *pos2;
        int result;
 
        if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
                return -EINVAL;
 
-       if (!tz || !cdev)
+       list_for_each_entry(pos1, &thermal_tz_list, node) {
+               if (pos1 == tz)
+                       break;
+       }
+       list_for_each_entry(pos2, &thermal_cdev_list, node) {
+               if (pos2 == cdev)
+                       break;
+       }
+
+       if (tz != pos1 || cdev != pos2)
                return -EINVAL;
 
        dev =
@@ -437,20 +448,20 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
        int result;
 
        if (strlen(type) >= THERMAL_NAME_LENGTH)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        if (!ops || !ops->get_max_state || !ops->get_cur_state ||
            !ops->set_cur_state)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
        if (!cdev)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
        if (result) {
                kfree(cdev);
-               return NULL;
+               return ERR_PTR(result);
        }
 
        strcpy(cdev->type, type);
@@ -462,7 +473,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
        if (result) {
                release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
                kfree(cdev);
-               return NULL;
+               return ERR_PTR(result);
        }
 
        /* sys I/F */
@@ -498,7 +509,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
       unregister:
        release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
        device_unregister(&cdev->device);
-       return NULL;
+       return ERR_PTR(result);
 }
 
 EXPORT_SYMBOL(thermal_cooling_device_register);
@@ -570,17 +581,17 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
        int count;
 
        if (strlen(type) >= THERMAL_NAME_LENGTH)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        if (trips > THERMAL_MAX_TRIPS || trips < 0)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        if (!ops || !ops->get_temp)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
        if (!tz)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        INIT_LIST_HEAD(&tz->cooling_devices);
        idr_init(&tz->idr);
@@ -588,7 +599,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
        result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
        if (result) {
                kfree(tz);
-               return NULL;
+               return ERR_PTR(result);
        }
 
        strcpy(tz->type, type);
@@ -601,7 +612,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
        if (result) {
                release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
                kfree(tz);
-               return NULL;
+               return ERR_PTR(result);
        }
 
        /* sys I/F */
@@ -643,7 +654,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
       unregister:
        release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
        device_unregister(&tz->device);
-       return NULL;
+       return ERR_PTR(result);
 }
 
 EXPORT_SYMBOL(thermal_zone_device_register);