Merge branch 'for-next' into for-linus
[safe/jmp/linux-2.6] / drivers / platform / x86 / thinkpad_acpi.c
index 215621c..c64e352 100644 (file)
@@ -286,6 +286,7 @@ struct ibm_init_struct {
        char param[32];
 
        int (*init) (struct ibm_init_struct *);
+       mode_t base_procfs_mode;
        struct ibm_struct *data;
 };
 
@@ -2082,6 +2083,7 @@ static struct attribute_set *hotkey_dev_attributes;
 
 static void tpacpi_driver_event(const unsigned int hkey_event);
 static void hotkey_driver_event(const unsigned int scancode);
+static void hotkey_poll_setup(const bool may_warn);
 
 /* HKEY.MHKG() return bits */
 #define TP_HOTKEY_TABLET_MASK (1 << 3)
@@ -2264,6 +2266,8 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask)
 
        rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) &
                                                        ~hotkey_source_mask);
+       hotkey_poll_setup(true);
+
        mutex_unlock(&hotkey_mutex);
 
        return rc;
@@ -2548,7 +2552,7 @@ static void hotkey_poll_stop_sync(void)
 }
 
 /* call with hotkey_mutex held */
-static void hotkey_poll_setup(bool may_warn)
+static void hotkey_poll_setup(const bool may_warn)
 {
        const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask;
        const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask;
@@ -2579,7 +2583,7 @@ static void hotkey_poll_setup(bool may_warn)
        }
 }
 
-static void hotkey_poll_setup_safe(bool may_warn)
+static void hotkey_poll_setup_safe(const bool may_warn)
 {
        mutex_lock(&hotkey_mutex);
        hotkey_poll_setup(may_warn);
@@ -2597,7 +2601,11 @@ static void hotkey_poll_set_freq(unsigned int freq)
 
 #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
 
-static void hotkey_poll_setup_safe(bool __unused)
+static void hotkey_poll_setup(const bool __unused)
+{
+}
+
+static void hotkey_poll_setup_safe(const bool __unused)
 {
 }
 
@@ -2607,16 +2615,11 @@ static int hotkey_inputdev_open(struct input_dev *dev)
 {
        switch (tpacpi_lifecycle) {
        case TPACPI_LIFE_INIT:
-               /*
-                * hotkey_init will call hotkey_poll_setup_safe
-                * at the appropriate moment
-                */
-               return 0;
-       case TPACPI_LIFE_EXITING:
-               return -EBUSY;
        case TPACPI_LIFE_RUNNING:
                hotkey_poll_setup_safe(false);
                return 0;
+       case TPACPI_LIFE_EXITING:
+               return -EBUSY;
        }
 
        /* Should only happen if tpacpi_lifecycle is corrupt */
@@ -2627,7 +2630,7 @@ static int hotkey_inputdev_open(struct input_dev *dev)
 static void hotkey_inputdev_close(struct input_dev *dev)
 {
        /* disable hotkey polling when possible */
-       if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING &&
+       if (tpacpi_lifecycle != TPACPI_LIFE_EXITING &&
            !(hotkey_source_mask & hotkey_driver_mask))
                hotkey_poll_setup_safe(false);
 }
@@ -3655,13 +3658,19 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        break;
                case 3:
                        /* 0x3000-0x3FFF: bay-related wakeups */
-                       if (hkey == TP_HKEY_EV_BAYEJ_ACK) {
+                       switch (hkey) {
+                       case TP_HKEY_EV_BAYEJ_ACK:
                                hotkey_autosleep_ack = 1;
                                printk(TPACPI_INFO
                                       "bay ejected\n");
                                hotkey_wakeup_hotunplug_complete_notify_change();
                                known_ev = true;
-                       } else {
+                               break;
+                       case TP_HKEY_EV_OPTDRV_EJ:
+                               /* FIXME: kick libata if SATA link offline */
+                               known_ev = true;
+                               break;
+                       default:
                                known_ev = false;
                        }
                        break;
@@ -3870,7 +3879,7 @@ enum {
        TP_ACPI_BLUETOOTH_HWPRESENT     = 0x01, /* Bluetooth hw available */
        TP_ACPI_BLUETOOTH_RADIOSSW      = 0x02, /* Bluetooth radio enabled */
        TP_ACPI_BLUETOOTH_RESUMECTRL    = 0x04, /* Bluetooth state at resume:
-                                                  off / last state */
+                                                  0 = disable, 1 = enable */
 };
 
 enum {
@@ -3916,10 +3925,11 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state)
        }
 #endif
 
-       /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
-       status = TP_ACPI_BLUETOOTH_RESUMECTRL;
        if (state == TPACPI_RFK_RADIO_ON)
-               status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+               status = TP_ACPI_BLUETOOTH_RADIOSSW
+                         | TP_ACPI_BLUETOOTH_RESUMECTRL;
+       else
+               status = 0;
 
        if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
                return -EIO;
@@ -4070,7 +4080,7 @@ enum {
        TP_ACPI_WANCARD_HWPRESENT       = 0x01, /* Wan hw available */
        TP_ACPI_WANCARD_RADIOSSW        = 0x02, /* Wan radio enabled */
        TP_ACPI_WANCARD_RESUMECTRL      = 0x04, /* Wan state at resume:
-                                                  off / last state */
+                                                  0 = disable, 1 = enable */
 };
 
 #define TPACPI_RFK_WWAN_SW_NAME                "tpacpi_wwan_sw"
@@ -4107,10 +4117,11 @@ static int wan_set_status(enum tpacpi_rfkill_state state)
        }
 #endif
 
-       /* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */
-       status = TP_ACPI_WANCARD_RESUMECTRL;
        if (state == TPACPI_RFK_RADIO_ON)
-               status |= TP_ACPI_WANCARD_RADIOSSW;
+               status = TP_ACPI_WANCARD_RADIOSSW
+                        | TP_ACPI_WANCARD_RESUMECTRL;
+       else
+               status = 0;
 
        if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
                return -EIO;
@@ -4619,6 +4630,10 @@ static int video_read(struct seq_file *m)
                return 0;
        }
 
+       /* Even reads can crash X.org, so... */
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        status = video_outputsw_get();
        if (status < 0)
                return status;
@@ -4652,6 +4667,10 @@ static int video_write(char *buf)
        if (video_supported == TPACPI_VIDEO_NONE)
                return -ENODEV;
 
+       /* Even reads can crash X.org, let alone writes... */
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        enable = 0;
        disable = 0;
 
@@ -5771,7 +5790,7 @@ static void thermal_exit(void)
        case TPACPI_THERMAL_ACPI_TMP07:
        case TPACPI_THERMAL_ACPI_UPDT:
                sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
-                                  &thermal_temp_input16_group);
+                                  &thermal_temp_input8_group);
                break;
        case TPACPI_THERMAL_NONE:
        default:
@@ -6133,13 +6152,13 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
        TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC),      /* T43/p ATI */
 
        /* Models with ATI GPUs that can use ECNVRAM */
-       TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC),
+       TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC),      /* R50,51 T40-42 */
        TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
-       TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+       TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_EC),      /* R52 */
        TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
 
        /* Models with Intel Extreme Graphics 2 */
-       TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC),
+       TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC),    /* X40 */
        TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
        TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
 
@@ -6522,7 +6541,8 @@ static int volume_set_status(const u8 status)
        return volume_set_status_ec(status);
 }
 
-static int volume_set_mute_ec(const bool mute)
+/* returns < 0 on error, 0 on no change, 1 on change */
+static int __volume_set_mute_ec(const bool mute)
 {
        int rc;
        u8 s, n;
@@ -6537,22 +6557,37 @@ static int volume_set_mute_ec(const bool mute)
        n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK :
                     s & ~TP_EC_AUDIO_MUTESW_MSK;
 
-       if (n != s)
+       if (n != s) {
                rc = volume_set_status_ec(n);
+               if (!rc)
+                       rc = 1;
+       }
 
 unlock:
        mutex_unlock(&volume_mutex);
        return rc;
 }
 
+static int volume_alsa_set_mute(const bool mute)
+{
+       dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n",
+                  (mute) ? "" : "un");
+       return __volume_set_mute_ec(mute);
+}
+
 static int volume_set_mute(const bool mute)
 {
+       int rc;
+
        dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n",
                   (mute) ? "" : "un");
-       return volume_set_mute_ec(mute);
+
+       rc = __volume_set_mute_ec(mute);
+       return (rc < 0) ? rc : 0;
 }
 
-static int volume_set_volume_ec(const u8 vol)
+/* returns < 0 on error, 0 on no change, 1 on change */
+static int __volume_set_volume_ec(const u8 vol)
 {
        int rc;
        u8 s, n;
@@ -6569,19 +6604,22 @@ static int volume_set_volume_ec(const u8 vol)
 
        n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol;
 
-       if (n != s)
+       if (n != s) {
                rc = volume_set_status_ec(n);
+               if (!rc)
+                       rc = 1;
+       }
 
 unlock:
        mutex_unlock(&volume_mutex);
        return rc;
 }
 
-static int volume_set_volume(const u8 vol)
+static int volume_alsa_set_volume(const u8 vol)
 {
        dbg_printk(TPACPI_DBG_MIXER,
-                  "trying to set volume level to %hu\n", vol);
-       return volume_set_volume_ec(vol);
+                  "ALSA: trying to set volume level to %hu\n", vol);
+       return __volume_set_volume_ec(vol);
 }
 
 static void volume_alsa_notify_change(void)
@@ -6628,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol,
 static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       return volume_set_volume(ucontrol->value.integer.value[0]);
+       return volume_alsa_set_volume(ucontrol->value.integer.value[0]);
 }
 
 #define volume_alsa_mute_info snd_ctl_boolean_mono_info
@@ -6651,7 +6689,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol,
 static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       return volume_set_mute(!ucontrol->value.integer.value[0]);
+       return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
 }
 
 static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {
@@ -8477,9 +8515,10 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
                "%s installed\n", ibm->name);
 
        if (ibm->read) {
-               mode_t mode;
+               mode_t mode = iibm->base_procfs_mode;
 
-               mode = S_IRUGO;
+               if (!mode)
+                       mode = S_IRUGO;
                if (ibm->write)
                        mode |= S_IWUSR;
                entry = proc_create_data(ibm->name, mode, proc_dir,
@@ -8670,6 +8709,7 @@ static struct ibm_init_struct ibms_init[] __initdata = {
 #ifdef CONFIG_THINKPAD_ACPI_VIDEO
        {
                .init = video_init,
+               .base_procfs_mode = S_IRUSR,
                .data = &video_driver_data,
        },
 #endif
@@ -9032,6 +9072,9 @@ static int __init thinkpad_acpi_module_init(void)
                        return ret;
                }
        }
+
+       tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
+
        ret = input_register_device(tpacpi_inputdev);
        if (ret < 0) {
                printk(TPACPI_ERR "unable to register input device\n");
@@ -9041,7 +9084,6 @@ static int __init thinkpad_acpi_module_init(void)
                tp_features.input_device_registered = 1;
        }
 
-       tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
        return 0;
 }