Commit a58db59a authored by Matthew Garrett's avatar Matthew Garrett

Merge branch 'for-upstream/platform-x86_tpacpi' of...

Merge branch 'for-upstream/platform-x86_tpacpi' of git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6 into x86-platform
parents 881a6c25 88cc8377
...@@ -650,6 +650,10 @@ LCD, CRT or DVI (if available). The following commands are available: ...@@ -650,6 +650,10 @@ LCD, CRT or DVI (if available). The following commands are available:
echo expand_toggle > /proc/acpi/ibm/video echo expand_toggle > /proc/acpi/ibm/video
echo video_switch > /proc/acpi/ibm/video echo video_switch > /proc/acpi/ibm/video
NOTE: Access to this feature is restricted to processes owning the
CAP_SYS_ADMIN capability for safety reasons, as it can interact badly
enough with some versions of X.org to crash it.
Each video output device can be enabled or disabled individually. Each video output device can be enabled or disabled individually.
Reading /proc/acpi/ibm/video shows the status of each device. Reading /proc/acpi/ibm/video shows the status of each device.
......
...@@ -322,9 +322,15 @@ config THINKPAD_ACPI_VIDEO ...@@ -322,9 +322,15 @@ config THINKPAD_ACPI_VIDEO
server running, phase of the moon, and the current mood of server running, phase of the moon, and the current mood of
Schroedinger's cat. If you can use X.org's RandR to control Schroedinger's cat. If you can use X.org's RandR to control
your ThinkPad's video output ports instead of this feature, your ThinkPad's video output ports instead of this feature,
don't think twice: do it and say N here to save some memory. don't think twice: do it and say N here to save memory and avoid
bad interactions with X.org.
If you are not sure, say Y here. NOTE: access to this feature is limited to processes with the
CAP_SYS_ADMIN capability, to avoid local DoS issues in platforms
where it interacts badly with X.org.
If you are not sure, say Y here but do try to check if you could
be using X.org RandR instead.
config THINKPAD_ACPI_HOTKEY_POLL config THINKPAD_ACPI_HOTKEY_POLL
bool "Support NVRAM polling for hot keys" bool "Support NVRAM polling for hot keys"
......
...@@ -286,6 +286,7 @@ struct ibm_init_struct { ...@@ -286,6 +286,7 @@ struct ibm_init_struct {
char param[32]; char param[32];
int (*init) (struct ibm_init_struct *); int (*init) (struct ibm_init_struct *);
mode_t base_procfs_mode;
struct ibm_struct *data; struct ibm_struct *data;
}; };
...@@ -2082,6 +2083,7 @@ static struct attribute_set *hotkey_dev_attributes; ...@@ -2082,6 +2083,7 @@ static struct attribute_set *hotkey_dev_attributes;
static void tpacpi_driver_event(const unsigned int hkey_event); static void tpacpi_driver_event(const unsigned int hkey_event);
static void hotkey_driver_event(const unsigned int scancode); static void hotkey_driver_event(const unsigned int scancode);
static void hotkey_poll_setup(const bool may_warn);
/* HKEY.MHKG() return bits */ /* HKEY.MHKG() return bits */
#define TP_HOTKEY_TABLET_MASK (1 << 3) #define TP_HOTKEY_TABLET_MASK (1 << 3)
...@@ -2264,6 +2266,8 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask) ...@@ -2264,6 +2266,8 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask)
rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) & rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) &
~hotkey_source_mask); ~hotkey_source_mask);
hotkey_poll_setup(true);
mutex_unlock(&hotkey_mutex); mutex_unlock(&hotkey_mutex);
return rc; return rc;
...@@ -2548,7 +2552,7 @@ static void hotkey_poll_stop_sync(void) ...@@ -2548,7 +2552,7 @@ static void hotkey_poll_stop_sync(void)
} }
/* call with hotkey_mutex held */ /* 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_driver_mask = hotkey_driver_mask & hotkey_source_mask;
const u32 poll_user_mask = hotkey_user_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) ...@@ -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); mutex_lock(&hotkey_mutex);
hotkey_poll_setup(may_warn); hotkey_poll_setup(may_warn);
...@@ -2597,7 +2601,11 @@ static void hotkey_poll_set_freq(unsigned int freq) ...@@ -2597,7 +2601,11 @@ static void hotkey_poll_set_freq(unsigned int freq)
#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ #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) ...@@ -2607,16 +2615,11 @@ static int hotkey_inputdev_open(struct input_dev *dev)
{ {
switch (tpacpi_lifecycle) { switch (tpacpi_lifecycle) {
case TPACPI_LIFE_INIT: 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: case TPACPI_LIFE_RUNNING:
hotkey_poll_setup_safe(false); hotkey_poll_setup_safe(false);
return 0; return 0;
case TPACPI_LIFE_EXITING:
return -EBUSY;
} }
/* Should only happen if tpacpi_lifecycle is corrupt */ /* Should only happen if tpacpi_lifecycle is corrupt */
...@@ -2627,7 +2630,7 @@ static int hotkey_inputdev_open(struct input_dev *dev) ...@@ -2627,7 +2630,7 @@ static int hotkey_inputdev_open(struct input_dev *dev)
static void hotkey_inputdev_close(struct input_dev *dev) static void hotkey_inputdev_close(struct input_dev *dev)
{ {
/* disable hotkey polling when possible */ /* disable hotkey polling when possible */
if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING && if (tpacpi_lifecycle != TPACPI_LIFE_EXITING &&
!(hotkey_source_mask & hotkey_driver_mask)) !(hotkey_source_mask & hotkey_driver_mask))
hotkey_poll_setup_safe(false); hotkey_poll_setup_safe(false);
} }
...@@ -3655,13 +3658,19 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) ...@@ -3655,13 +3658,19 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
break; break;
case 3: case 3:
/* 0x3000-0x3FFF: bay-related wakeups */ /* 0x3000-0x3FFF: bay-related wakeups */
if (hkey == TP_HKEY_EV_BAYEJ_ACK) { switch (hkey) {
case TP_HKEY_EV_BAYEJ_ACK:
hotkey_autosleep_ack = 1; hotkey_autosleep_ack = 1;
printk(TPACPI_INFO printk(TPACPI_INFO
"bay ejected\n"); "bay ejected\n");
hotkey_wakeup_hotunplug_complete_notify_change(); hotkey_wakeup_hotunplug_complete_notify_change();
known_ev = true; 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; known_ev = false;
} }
break; break;
...@@ -3870,7 +3879,7 @@ enum { ...@@ -3870,7 +3879,7 @@ enum {
TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume: TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume:
off / last state */ 0 = disable, 1 = enable */
}; };
enum { enum {
...@@ -3916,10 +3925,11 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state) ...@@ -3916,10 +3925,11 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state)
} }
#endif #endif
/* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
status = TP_ACPI_BLUETOOTH_RESUMECTRL;
if (state == TPACPI_RFK_RADIO_ON) 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)) if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
return -EIO; return -EIO;
...@@ -4070,7 +4080,7 @@ enum { ...@@ -4070,7 +4080,7 @@ enum {
TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume: 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" #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw"
...@@ -4107,10 +4117,11 @@ static int wan_set_status(enum tpacpi_rfkill_state state) ...@@ -4107,10 +4117,11 @@ static int wan_set_status(enum tpacpi_rfkill_state state)
} }
#endif #endif
/* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */
status = TP_ACPI_WANCARD_RESUMECTRL;
if (state == TPACPI_RFK_RADIO_ON) 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)) if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
return -EIO; return -EIO;
...@@ -4619,6 +4630,10 @@ static int video_read(struct seq_file *m) ...@@ -4619,6 +4630,10 @@ static int video_read(struct seq_file *m)
return 0; return 0;
} }
/* Even reads can crash X.org, so... */
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
status = video_outputsw_get(); status = video_outputsw_get();
if (status < 0) if (status < 0)
return status; return status;
...@@ -4652,6 +4667,10 @@ static int video_write(char *buf) ...@@ -4652,6 +4667,10 @@ static int video_write(char *buf)
if (video_supported == TPACPI_VIDEO_NONE) if (video_supported == TPACPI_VIDEO_NONE)
return -ENODEV; return -ENODEV;
/* Even reads can crash X.org, let alone writes... */
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
enable = 0; enable = 0;
disable = 0; disable = 0;
...@@ -6133,13 +6152,13 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { ...@@ -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 */ TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
/* Models with ATI GPUs that can use ECNVRAM */ /* 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('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), TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
/* Models with Intel Extreme Graphics 2 */ /* 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', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
TPACPI_Q_IBM('1', 'W', 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) ...@@ -6522,7 +6541,8 @@ static int volume_set_status(const u8 status)
return volume_set_status_ec(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; int rc;
u8 s, n; u8 s, n;
...@@ -6537,22 +6557,37 @@ static int volume_set_mute_ec(const bool mute) ...@@ -6537,22 +6557,37 @@ static int volume_set_mute_ec(const bool mute)
n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK :
s & ~TP_EC_AUDIO_MUTESW_MSK; s & ~TP_EC_AUDIO_MUTESW_MSK;
if (n != s) if (n != s) {
rc = volume_set_status_ec(n); rc = volume_set_status_ec(n);
if (!rc)
rc = 1;
}
unlock: unlock:
mutex_unlock(&volume_mutex); mutex_unlock(&volume_mutex);
return rc; 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) static int volume_set_mute(const bool mute)
{ {
int rc;
dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n",
(mute) ? "" : "un"); (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; int rc;
u8 s, n; u8 s, n;
...@@ -6569,19 +6604,22 @@ static int volume_set_volume_ec(const u8 vol) ...@@ -6569,19 +6604,22 @@ static int volume_set_volume_ec(const u8 vol)
n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol;
if (n != s) if (n != s) {
rc = volume_set_status_ec(n); rc = volume_set_status_ec(n);
if (!rc)
rc = 1;
}
unlock: unlock:
mutex_unlock(&volume_mutex); mutex_unlock(&volume_mutex);
return rc; return rc;
} }
static int volume_set_volume(const u8 vol) static int volume_alsa_set_volume(const u8 vol)
{ {
dbg_printk(TPACPI_DBG_MIXER, dbg_printk(TPACPI_DBG_MIXER,
"trying to set volume level to %hu\n", vol); "ALSA: trying to set volume level to %hu\n", vol);
return volume_set_volume_ec(vol); return __volume_set_volume_ec(vol);
} }
static void volume_alsa_notify_change(void) static void volume_alsa_notify_change(void)
...@@ -6628,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol, ...@@ -6628,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol,
static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) 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 #define volume_alsa_mute_info snd_ctl_boolean_mono_info
...@@ -6651,7 +6689,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol, ...@@ -6651,7 +6689,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol,
static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) 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 = { static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {
...@@ -8477,9 +8515,10 @@ static int __init ibm_init(struct ibm_init_struct *iibm) ...@@ -8477,9 +8515,10 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
"%s installed\n", ibm->name); "%s installed\n", ibm->name);
if (ibm->read) { if (ibm->read) {
mode_t mode; mode_t mode = iibm->base_procfs_mode;
mode = S_IRUGO; if (!mode)
mode = S_IRUGO;
if (ibm->write) if (ibm->write)
mode |= S_IWUSR; mode |= S_IWUSR;
entry = proc_create_data(ibm->name, mode, proc_dir, entry = proc_create_data(ibm->name, mode, proc_dir,
...@@ -8670,6 +8709,7 @@ static struct ibm_init_struct ibms_init[] __initdata = { ...@@ -8670,6 +8709,7 @@ static struct ibm_init_struct ibms_init[] __initdata = {
#ifdef CONFIG_THINKPAD_ACPI_VIDEO #ifdef CONFIG_THINKPAD_ACPI_VIDEO
{ {
.init = video_init, .init = video_init,
.base_procfs_mode = S_IRUSR,
.data = &video_driver_data, .data = &video_driver_data,
}, },
#endif #endif
...@@ -9032,6 +9072,9 @@ static int __init thinkpad_acpi_module_init(void) ...@@ -9032,6 +9072,9 @@ static int __init thinkpad_acpi_module_init(void)
return ret; return ret;
} }
} }
tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
ret = input_register_device(tpacpi_inputdev); ret = input_register_device(tpacpi_inputdev);
if (ret < 0) { if (ret < 0) {
printk(TPACPI_ERR "unable to register input device\n"); printk(TPACPI_ERR "unable to register input device\n");
...@@ -9041,7 +9084,6 @@ static int __init thinkpad_acpi_module_init(void) ...@@ -9041,7 +9084,6 @@ static int __init thinkpad_acpi_module_init(void)
tp_features.input_device_registered = 1; tp_features.input_device_registered = 1;
} }
tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment