aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2010-03-02 09:51:48 -0500
committerMatthew Garrett <mjg@redhat.com>2010-03-02 09:51:48 -0500
commita58db59a263d4232710af816f3857254b5823633 (patch)
tree977120471e3d34412d2c810c48d0fe2b9547ffc7 /drivers/platform/x86
parent881a6c25a8453388e3190de94a5e105439a9f806 (diff)
parent88cc83772a3c7756b9f2b4ba835545ad90a08409 (diff)
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
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r--drivers/platform/x86/Kconfig10
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c116
2 files changed, 87 insertions, 39 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index aef4f17cdfd4..92161c7ff4b7 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -322,9 +322,15 @@ config THINKPAD_ACPI_VIDEO
322 server running, phase of the moon, and the current mood of 322 server running, phase of the moon, and the current mood of
323 Schroedinger's cat. If you can use X.org's RandR to control 323 Schroedinger's cat. If you can use X.org's RandR to control
324 your ThinkPad's video output ports instead of this feature, 324 your ThinkPad's video output ports instead of this feature,
325 don't think twice: do it and say N here to save some memory. 325 don't think twice: do it and say N here to save memory and avoid
326 bad interactions with X.org.
326 327
327 If you are not sure, say Y here. 328 NOTE: access to this feature is limited to processes with the
329 CAP_SYS_ADMIN capability, to avoid local DoS issues in platforms
330 where it interacts badly with X.org.
331
332 If you are not sure, say Y here but do try to check if you could
333 be using X.org RandR instead.
328 334
329config THINKPAD_ACPI_HOTKEY_POLL 335config THINKPAD_ACPI_HOTKEY_POLL
330 bool "Support NVRAM polling for hot keys" 336 bool "Support NVRAM polling for hot keys"
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index eb603f1d55ca..e7b0c3bcef89 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -286,6 +286,7 @@ struct ibm_init_struct {
286 char param[32]; 286 char param[32];
287 287
288 int (*init) (struct ibm_init_struct *); 288 int (*init) (struct ibm_init_struct *);
289 mode_t base_procfs_mode;
289 struct ibm_struct *data; 290 struct ibm_struct *data;
290}; 291};
291 292
@@ -2082,6 +2083,7 @@ static struct attribute_set *hotkey_dev_attributes;
2082 2083
2083static void tpacpi_driver_event(const unsigned int hkey_event); 2084static void tpacpi_driver_event(const unsigned int hkey_event);
2084static void hotkey_driver_event(const unsigned int scancode); 2085static void hotkey_driver_event(const unsigned int scancode);
2086static void hotkey_poll_setup(const bool may_warn);
2085 2087
2086/* HKEY.MHKG() return bits */ 2088/* HKEY.MHKG() return bits */
2087#define TP_HOTKEY_TABLET_MASK (1 << 3) 2089#define TP_HOTKEY_TABLET_MASK (1 << 3)
@@ -2264,6 +2266,8 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask)
2264 2266
2265 rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) & 2267 rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) &
2266 ~hotkey_source_mask); 2268 ~hotkey_source_mask);
2269 hotkey_poll_setup(true);
2270
2267 mutex_unlock(&hotkey_mutex); 2271 mutex_unlock(&hotkey_mutex);
2268 2272
2269 return rc; 2273 return rc;
@@ -2548,7 +2552,7 @@ static void hotkey_poll_stop_sync(void)
2548} 2552}
2549 2553
2550/* call with hotkey_mutex held */ 2554/* call with hotkey_mutex held */
2551static void hotkey_poll_setup(bool may_warn) 2555static void hotkey_poll_setup(const bool may_warn)
2552{ 2556{
2553 const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask; 2557 const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask;
2554 const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask; 2558 const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask;
@@ -2579,7 +2583,7 @@ static void hotkey_poll_setup(bool may_warn)
2579 } 2583 }
2580} 2584}
2581 2585
2582static void hotkey_poll_setup_safe(bool may_warn) 2586static void hotkey_poll_setup_safe(const bool may_warn)
2583{ 2587{
2584 mutex_lock(&hotkey_mutex); 2588 mutex_lock(&hotkey_mutex);
2585 hotkey_poll_setup(may_warn); 2589 hotkey_poll_setup(may_warn);
@@ -2597,7 +2601,11 @@ static void hotkey_poll_set_freq(unsigned int freq)
2597 2601
2598#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ 2602#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
2599 2603
2600static void hotkey_poll_setup_safe(bool __unused) 2604static void hotkey_poll_setup(const bool __unused)
2605{
2606}
2607
2608static void hotkey_poll_setup_safe(const bool __unused)
2601{ 2609{
2602} 2610}
2603 2611
@@ -2607,16 +2615,11 @@ static int hotkey_inputdev_open(struct input_dev *dev)
2607{ 2615{
2608 switch (tpacpi_lifecycle) { 2616 switch (tpacpi_lifecycle) {
2609 case TPACPI_LIFE_INIT: 2617 case TPACPI_LIFE_INIT:
2610 /*
2611 * hotkey_init will call hotkey_poll_setup_safe
2612 * at the appropriate moment
2613 */
2614 return 0;
2615 case TPACPI_LIFE_EXITING:
2616 return -EBUSY;
2617 case TPACPI_LIFE_RUNNING: 2618 case TPACPI_LIFE_RUNNING:
2618 hotkey_poll_setup_safe(false); 2619 hotkey_poll_setup_safe(false);
2619 return 0; 2620 return 0;
2621 case TPACPI_LIFE_EXITING:
2622 return -EBUSY;
2620 } 2623 }
2621 2624
2622 /* Should only happen if tpacpi_lifecycle is corrupt */ 2625 /* Should only happen if tpacpi_lifecycle is corrupt */
@@ -2627,7 +2630,7 @@ static int hotkey_inputdev_open(struct input_dev *dev)
2627static void hotkey_inputdev_close(struct input_dev *dev) 2630static void hotkey_inputdev_close(struct input_dev *dev)
2628{ 2631{
2629 /* disable hotkey polling when possible */ 2632 /* disable hotkey polling when possible */
2630 if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING && 2633 if (tpacpi_lifecycle != TPACPI_LIFE_EXITING &&
2631 !(hotkey_source_mask & hotkey_driver_mask)) 2634 !(hotkey_source_mask & hotkey_driver_mask))
2632 hotkey_poll_setup_safe(false); 2635 hotkey_poll_setup_safe(false);
2633} 2636}
@@ -3655,13 +3658,19 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
3655 break; 3658 break;
3656 case 3: 3659 case 3:
3657 /* 0x3000-0x3FFF: bay-related wakeups */ 3660 /* 0x3000-0x3FFF: bay-related wakeups */
3658 if (hkey == TP_HKEY_EV_BAYEJ_ACK) { 3661 switch (hkey) {
3662 case TP_HKEY_EV_BAYEJ_ACK:
3659 hotkey_autosleep_ack = 1; 3663 hotkey_autosleep_ack = 1;
3660 printk(TPACPI_INFO 3664 printk(TPACPI_INFO
3661 "bay ejected\n"); 3665 "bay ejected\n");
3662 hotkey_wakeup_hotunplug_complete_notify_change(); 3666 hotkey_wakeup_hotunplug_complete_notify_change();
3663 known_ev = true; 3667 known_ev = true;
3664 } else { 3668 break;
3669 case TP_HKEY_EV_OPTDRV_EJ:
3670 /* FIXME: kick libata if SATA link offline */
3671 known_ev = true;
3672 break;
3673 default:
3665 known_ev = false; 3674 known_ev = false;
3666 } 3675 }
3667 break; 3676 break;
@@ -3870,7 +3879,7 @@ enum {
3870 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ 3879 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
3871 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ 3880 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
3872 TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume: 3881 TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume:
3873 off / last state */ 3882 0 = disable, 1 = enable */
3874}; 3883};
3875 3884
3876enum { 3885enum {
@@ -3916,10 +3925,11 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state)
3916 } 3925 }
3917#endif 3926#endif
3918 3927
3919 /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
3920 status = TP_ACPI_BLUETOOTH_RESUMECTRL;
3921 if (state == TPACPI_RFK_RADIO_ON) 3928 if (state == TPACPI_RFK_RADIO_ON)
3922 status |= TP_ACPI_BLUETOOTH_RADIOSSW; 3929 status = TP_ACPI_BLUETOOTH_RADIOSSW
3930 | TP_ACPI_BLUETOOTH_RESUMECTRL;
3931 else
3932 status = 0;
3923 3933
3924 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) 3934 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
3925 return -EIO; 3935 return -EIO;
@@ -4070,7 +4080,7 @@ enum {
4070 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ 4080 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
4071 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ 4081 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
4072 TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume: 4082 TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume:
4073 off / last state */ 4083 0 = disable, 1 = enable */
4074}; 4084};
4075 4085
4076#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" 4086#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw"
@@ -4107,10 +4117,11 @@ static int wan_set_status(enum tpacpi_rfkill_state state)
4107 } 4117 }
4108#endif 4118#endif
4109 4119
4110 /* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */
4111 status = TP_ACPI_WANCARD_RESUMECTRL;
4112 if (state == TPACPI_RFK_RADIO_ON) 4120 if (state == TPACPI_RFK_RADIO_ON)
4113 status |= TP_ACPI_WANCARD_RADIOSSW; 4121 status = TP_ACPI_WANCARD_RADIOSSW
4122 | TP_ACPI_WANCARD_RESUMECTRL;
4123 else
4124 status = 0;
4114 4125
4115 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) 4126 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
4116 return -EIO; 4127 return -EIO;
@@ -4619,6 +4630,10 @@ static int video_read(struct seq_file *m)
4619 return 0; 4630 return 0;
4620 } 4631 }
4621 4632
4633 /* Even reads can crash X.org, so... */
4634 if (!capable(CAP_SYS_ADMIN))
4635 return -EPERM;
4636
4622 status = video_outputsw_get(); 4637 status = video_outputsw_get();
4623 if (status < 0) 4638 if (status < 0)
4624 return status; 4639 return status;
@@ -4652,6 +4667,10 @@ static int video_write(char *buf)
4652 if (video_supported == TPACPI_VIDEO_NONE) 4667 if (video_supported == TPACPI_VIDEO_NONE)
4653 return -ENODEV; 4668 return -ENODEV;
4654 4669
4670 /* Even reads can crash X.org, let alone writes... */
4671 if (!capable(CAP_SYS_ADMIN))
4672 return -EPERM;
4673
4655 enable = 0; 4674 enable = 0;
4656 disable = 0; 4675 disable = 0;
4657 4676
@@ -6133,13 +6152,13 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
6133 TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */ 6152 TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
6134 6153
6135 /* Models with ATI GPUs that can use ECNVRAM */ 6154 /* Models with ATI GPUs that can use ECNVRAM */
6136 TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), 6155 TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), /* R50,51 T40-42 */
6137 TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 6156 TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
6138 TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 6157 TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_EC), /* R52 */
6139 TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 6158 TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
6140 6159
6141 /* Models with Intel Extreme Graphics 2 */ 6160 /* Models with Intel Extreme Graphics 2 */
6142 TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), 6161 TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), /* X40 */
6143 TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 6162 TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
6144 TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), 6163 TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
6145 6164
@@ -6522,7 +6541,8 @@ static int volume_set_status(const u8 status)
6522 return volume_set_status_ec(status); 6541 return volume_set_status_ec(status);
6523} 6542}
6524 6543
6525static int volume_set_mute_ec(const bool mute) 6544/* returns < 0 on error, 0 on no change, 1 on change */
6545static int __volume_set_mute_ec(const bool mute)
6526{ 6546{
6527 int rc; 6547 int rc;
6528 u8 s, n; 6548 u8 s, n;
@@ -6537,22 +6557,37 @@ static int volume_set_mute_ec(const bool mute)
6537 n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : 6557 n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK :
6538 s & ~TP_EC_AUDIO_MUTESW_MSK; 6558 s & ~TP_EC_AUDIO_MUTESW_MSK;
6539 6559
6540 if (n != s) 6560 if (n != s) {
6541 rc = volume_set_status_ec(n); 6561 rc = volume_set_status_ec(n);
6562 if (!rc)
6563 rc = 1;
6564 }
6542 6565
6543unlock: 6566unlock:
6544 mutex_unlock(&volume_mutex); 6567 mutex_unlock(&volume_mutex);
6545 return rc; 6568 return rc;
6546} 6569}
6547 6570
6571static int volume_alsa_set_mute(const bool mute)
6572{
6573 dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n",
6574 (mute) ? "" : "un");
6575 return __volume_set_mute_ec(mute);
6576}
6577
6548static int volume_set_mute(const bool mute) 6578static int volume_set_mute(const bool mute)
6549{ 6579{
6580 int rc;
6581
6550 dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", 6582 dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n",
6551 (mute) ? "" : "un"); 6583 (mute) ? "" : "un");
6552 return volume_set_mute_ec(mute); 6584
6585 rc = __volume_set_mute_ec(mute);
6586 return (rc < 0) ? rc : 0;
6553} 6587}
6554 6588
6555static int volume_set_volume_ec(const u8 vol) 6589/* returns < 0 on error, 0 on no change, 1 on change */
6590static int __volume_set_volume_ec(const u8 vol)
6556{ 6591{
6557 int rc; 6592 int rc;
6558 u8 s, n; 6593 u8 s, n;
@@ -6569,19 +6604,22 @@ static int volume_set_volume_ec(const u8 vol)
6569 6604
6570 n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; 6605 n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol;
6571 6606
6572 if (n != s) 6607 if (n != s) {
6573 rc = volume_set_status_ec(n); 6608 rc = volume_set_status_ec(n);
6609 if (!rc)
6610 rc = 1;
6611 }
6574 6612
6575unlock: 6613unlock:
6576 mutex_unlock(&volume_mutex); 6614 mutex_unlock(&volume_mutex);
6577 return rc; 6615 return rc;
6578} 6616}
6579 6617
6580static int volume_set_volume(const u8 vol) 6618static int volume_alsa_set_volume(const u8 vol)
6581{ 6619{
6582 dbg_printk(TPACPI_DBG_MIXER, 6620 dbg_printk(TPACPI_DBG_MIXER,
6583 "trying to set volume level to %hu\n", vol); 6621 "ALSA: trying to set volume level to %hu\n", vol);
6584 return volume_set_volume_ec(vol); 6622 return __volume_set_volume_ec(vol);
6585} 6623}
6586 6624
6587static void volume_alsa_notify_change(void) 6625static void volume_alsa_notify_change(void)
@@ -6628,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol,
6628static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, 6666static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol,
6629 struct snd_ctl_elem_value *ucontrol) 6667 struct snd_ctl_elem_value *ucontrol)
6630{ 6668{
6631 return volume_set_volume(ucontrol->value.integer.value[0]); 6669 return volume_alsa_set_volume(ucontrol->value.integer.value[0]);
6632} 6670}
6633 6671
6634#define volume_alsa_mute_info snd_ctl_boolean_mono_info 6672#define volume_alsa_mute_info snd_ctl_boolean_mono_info
@@ -6651,7 +6689,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol,
6651static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, 6689static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
6652 struct snd_ctl_elem_value *ucontrol) 6690 struct snd_ctl_elem_value *ucontrol)
6653{ 6691{
6654 return volume_set_mute(!ucontrol->value.integer.value[0]); 6692 return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
6655} 6693}
6656 6694
6657static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { 6695static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {
@@ -8477,9 +8515,10 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
8477 "%s installed\n", ibm->name); 8515 "%s installed\n", ibm->name);
8478 8516
8479 if (ibm->read) { 8517 if (ibm->read) {
8480 mode_t mode; 8518 mode_t mode = iibm->base_procfs_mode;
8481 8519
8482 mode = S_IRUGO; 8520 if (!mode)
8521 mode = S_IRUGO;
8483 if (ibm->write) 8522 if (ibm->write)
8484 mode |= S_IWUSR; 8523 mode |= S_IWUSR;
8485 entry = proc_create_data(ibm->name, mode, proc_dir, 8524 entry = proc_create_data(ibm->name, mode, proc_dir,
@@ -8670,6 +8709,7 @@ static struct ibm_init_struct ibms_init[] __initdata = {
8670#ifdef CONFIG_THINKPAD_ACPI_VIDEO 8709#ifdef CONFIG_THINKPAD_ACPI_VIDEO
8671 { 8710 {
8672 .init = video_init, 8711 .init = video_init,
8712 .base_procfs_mode = S_IRUSR,
8673 .data = &video_driver_data, 8713 .data = &video_driver_data,
8674 }, 8714 },
8675#endif 8715#endif
@@ -9032,6 +9072,9 @@ static int __init thinkpad_acpi_module_init(void)
9032 return ret; 9072 return ret;
9033 } 9073 }
9034 } 9074 }
9075
9076 tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
9077
9035 ret = input_register_device(tpacpi_inputdev); 9078 ret = input_register_device(tpacpi_inputdev);
9036 if (ret < 0) { 9079 if (ret < 0) {
9037 printk(TPACPI_ERR "unable to register input device\n"); 9080 printk(TPACPI_ERR "unable to register input device\n");
@@ -9041,7 +9084,6 @@ static int __init thinkpad_acpi_module_init(void)
9041 tp_features.input_device_registered = 1; 9084 tp_features.input_device_registered = 1;
9042 } 9085 }
9043 9086
9044 tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
9045 return 0; 9087 return 0;
9046} 9088}
9047 9089