aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c159
1 files changed, 132 insertions, 27 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a2f5312c6a4e..4d909d5a0340 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -22,7 +22,7 @@
22 */ 22 */
23 23
24#define TPACPI_VERSION "0.23" 24#define TPACPI_VERSION "0.23"
25#define TPACPI_SYSFS_VERSION 0x020600 25#define TPACPI_SYSFS_VERSION 0x020700
26 26
27/* 27/*
28 * Changelog: 28 * Changelog:
@@ -299,6 +299,7 @@ static struct {
299 u32 fan_ctrl_status_undef:1; 299 u32 fan_ctrl_status_undef:1;
300 u32 second_fan:1; 300 u32 second_fan:1;
301 u32 beep_needs_two_args:1; 301 u32 beep_needs_two_args:1;
302 u32 mixer_no_level_control:1;
302 u32 input_device_registered:1; 303 u32 input_device_registered:1;
303 u32 platform_drv_registered:1; 304 u32 platform_drv_registered:1;
304 u32 platform_drv_attrs_registered:1; 305 u32 platform_drv_attrs_registered:1;
@@ -426,6 +427,12 @@ static void tpacpi_log_usertask(const char * const what)
426 .ec = TPACPI_MATCH_ANY, \ 427 .ec = TPACPI_MATCH_ANY, \
427 .quirks = (__quirk) } 428 .quirks = (__quirk) }
428 429
430#define TPACPI_QEC_LNV(__id1, __id2, __quirk) \
431 { .vendor = PCI_VENDOR_ID_LENOVO, \
432 .bios = TPACPI_MATCH_ANY, \
433 .ec = TPID(__id1, __id2), \
434 .quirks = (__quirk) }
435
429struct tpacpi_quirk { 436struct tpacpi_quirk {
430 unsigned int vendor; 437 unsigned int vendor;
431 u16 bios; 438 u16 bios;
@@ -6416,9 +6423,17 @@ enum tpacpi_volume_access_mode {
6416 TPACPI_VOL_MODE_MAX 6423 TPACPI_VOL_MODE_MAX
6417}; 6424};
6418 6425
6426enum tpacpi_volume_capabilities {
6427 TPACPI_VOL_CAP_AUTO = 0, /* Use white/blacklist */
6428 TPACPI_VOL_CAP_VOLMUTE, /* Output vol and mute */
6429 TPACPI_VOL_CAP_MUTEONLY, /* Output mute only */
6430 TPACPI_VOL_CAP_MAX
6431};
6432
6419static enum tpacpi_volume_access_mode volume_mode = 6433static enum tpacpi_volume_access_mode volume_mode =
6420 TPACPI_VOL_MODE_MAX; 6434 TPACPI_VOL_MODE_MAX;
6421 6435
6436static enum tpacpi_volume_capabilities volume_capabilities;
6422 6437
6423/* 6438/*
6424 * Used to syncronize writers to TP_EC_AUDIO and 6439 * Used to syncronize writers to TP_EC_AUDIO and
@@ -6430,7 +6445,7 @@ static void tpacpi_volume_checkpoint_nvram(void)
6430{ 6445{
6431 u8 lec = 0; 6446 u8 lec = 0;
6432 u8 b_nvram; 6447 u8 b_nvram;
6433 const u8 ec_mask = TP_EC_AUDIO_LVL_MSK | TP_EC_AUDIO_MUTESW_MSK; 6448 u8 ec_mask;
6434 6449
6435 if (volume_mode != TPACPI_VOL_MODE_ECNVRAM) 6450 if (volume_mode != TPACPI_VOL_MODE_ECNVRAM)
6436 return; 6451 return;
@@ -6438,6 +6453,11 @@ static void tpacpi_volume_checkpoint_nvram(void)
6438 vdbg_printk(TPACPI_DBG_MIXER, 6453 vdbg_printk(TPACPI_DBG_MIXER,
6439 "trying to checkpoint mixer state to NVRAM...\n"); 6454 "trying to checkpoint mixer state to NVRAM...\n");
6440 6455
6456 if (tp_features.mixer_no_level_control)
6457 ec_mask = TP_EC_AUDIO_MUTESW_MSK;
6458 else
6459 ec_mask = TP_EC_AUDIO_MUTESW_MSK | TP_EC_AUDIO_LVL_MSK;
6460
6441 if (mutex_lock_killable(&volume_mutex) < 0) 6461 if (mutex_lock_killable(&volume_mutex) < 0)
6442 return; 6462 return;
6443 6463
@@ -6575,8 +6595,36 @@ static void volume_exit(void)
6575 tpacpi_volume_checkpoint_nvram(); 6595 tpacpi_volume_checkpoint_nvram();
6576} 6596}
6577 6597
6598#define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */
6599#define TPACPI_VOL_Q_LEVEL 0x0002 /* Volume control available */
6600
6601static const struct tpacpi_quirk volume_quirk_table[] __initconst = {
6602 /* Whitelist volume level on all IBM by default */
6603 { .vendor = PCI_VENDOR_ID_IBM,
6604 .bios = TPACPI_MATCH_ANY,
6605 .ec = TPACPI_MATCH_ANY,
6606 .quirks = TPACPI_VOL_Q_LEVEL },
6607
6608 /* Lenovo models with volume control (needs confirmation) */
6609 TPACPI_QEC_LNV('7', 'C', TPACPI_VOL_Q_LEVEL), /* R60/i */
6610 TPACPI_QEC_LNV('7', 'E', TPACPI_VOL_Q_LEVEL), /* R60e/i */
6611 TPACPI_QEC_LNV('7', '9', TPACPI_VOL_Q_LEVEL), /* T60/p */
6612 TPACPI_QEC_LNV('7', 'B', TPACPI_VOL_Q_LEVEL), /* X60/s */
6613 TPACPI_QEC_LNV('7', 'J', TPACPI_VOL_Q_LEVEL), /* X60t */
6614 TPACPI_QEC_LNV('7', '7', TPACPI_VOL_Q_LEVEL), /* Z60 */
6615 TPACPI_QEC_LNV('7', 'F', TPACPI_VOL_Q_LEVEL), /* Z61 */
6616
6617 /* Whitelist mute-only on all Lenovo by default */
6618 { .vendor = PCI_VENDOR_ID_LENOVO,
6619 .bios = TPACPI_MATCH_ANY,
6620 .ec = TPACPI_MATCH_ANY,
6621 .quirks = TPACPI_VOL_Q_MUTEONLY }
6622};
6623
6578static int __init volume_init(struct ibm_init_struct *iibm) 6624static int __init volume_init(struct ibm_init_struct *iibm)
6579{ 6625{
6626 unsigned long quirks;
6627
6580 vdbg_printk(TPACPI_DBG_INIT, "initializing volume subdriver\n"); 6628 vdbg_printk(TPACPI_DBG_INIT, "initializing volume subdriver\n");
6581 6629
6582 mutex_init(&volume_mutex); 6630 mutex_init(&volume_mutex);
@@ -6596,6 +6644,36 @@ static int __init volume_init(struct ibm_init_struct *iibm)
6596 return 1; 6644 return 1;
6597 } 6645 }
6598 6646
6647 if (volume_capabilities >= TPACPI_VOL_CAP_MAX)
6648 return -EINVAL;
6649
6650 quirks = tpacpi_check_quirks(volume_quirk_table,
6651 ARRAY_SIZE(volume_quirk_table));
6652
6653 switch (volume_capabilities) {
6654 case TPACPI_VOL_CAP_AUTO:
6655 if (quirks & TPACPI_VOL_Q_MUTEONLY)
6656 tp_features.mixer_no_level_control = 1;
6657 else if (quirks & TPACPI_VOL_Q_LEVEL)
6658 tp_features.mixer_no_level_control = 0;
6659 else
6660 return 1; /* no mixer */
6661 break;
6662 case TPACPI_VOL_CAP_VOLMUTE:
6663 tp_features.mixer_no_level_control = 0;
6664 break;
6665 case TPACPI_VOL_CAP_MUTEONLY:
6666 tp_features.mixer_no_level_control = 1;
6667 break;
6668 default:
6669 return 1;
6670 }
6671
6672 if (volume_capabilities != TPACPI_VOL_CAP_AUTO)
6673 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
6674 "using user-supplied volume_capabilities=%d\n",
6675 volume_capabilities);
6676
6599 if (volume_mode == TPACPI_VOL_MODE_AUTO || 6677 if (volume_mode == TPACPI_VOL_MODE_AUTO ||
6600 volume_mode == TPACPI_VOL_MODE_MAX) { 6678 volume_mode == TPACPI_VOL_MODE_MAX) {
6601 volume_mode = TPACPI_VOL_MODE_ECNVRAM; 6679 volume_mode = TPACPI_VOL_MODE_ECNVRAM;
@@ -6610,7 +6688,8 @@ static int __init volume_init(struct ibm_init_struct *iibm)
6610 } 6688 }
6611 6689
6612 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, 6690 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
6613 "volume is supported\n"); 6691 "mute is supported, volume control is %s\n",
6692 str_supported(!tp_features.mixer_no_level_control));
6614 6693
6615 return 0; 6694 return 0;
6616} 6695}
@@ -6623,13 +6702,21 @@ static int volume_read(char *p)
6623 if (volume_get_status(&status) < 0) { 6702 if (volume_get_status(&status) < 0) {
6624 len += sprintf(p + len, "level:\t\tunreadable\n"); 6703 len += sprintf(p + len, "level:\t\tunreadable\n");
6625 } else { 6704 } else {
6626 len += sprintf(p + len, "level:\t\t%d\n", 6705 if (tp_features.mixer_no_level_control)
6627 status & TP_EC_AUDIO_LVL_MSK); 6706 len += sprintf(p + len, "level:\t\tunsupported\n");
6707 else
6708 len += sprintf(p + len, "level:\t\t%d\n",
6709 status & TP_EC_AUDIO_LVL_MSK);
6710
6628 len += sprintf(p + len, "mute:\t\t%s\n", 6711 len += sprintf(p + len, "mute:\t\t%s\n",
6629 onoff(status, TP_EC_AUDIO_MUTESW)); 6712 onoff(status, TP_EC_AUDIO_MUTESW));
6630 len += sprintf(p + len, "commands:\tup, down, mute\n"); 6713
6631 len += sprintf(p + len, "commands:\tlevel <level>" 6714 len += sprintf(p + len, "commands:\tunmute, mute\n");
6715 if (!tp_features.mixer_no_level_control) {
6716 len += sprintf(p + len, "commands:\tup, down\n");
6717 len += sprintf(p + len, "commands:\tlevel <level>"
6632 " (<level> is 0-%d)\n", TP_EC_VOLUME_MAX); 6718 " (<level> is 0-%d)\n", TP_EC_VOLUME_MAX);
6719 }
6633 } 6720 }
6634 6721
6635 return len; 6722 return len;
@@ -6651,30 +6738,43 @@ static int volume_write(char *buf)
6651 new_mute = s & TP_EC_AUDIO_MUTESW_MSK; 6738 new_mute = s & TP_EC_AUDIO_MUTESW_MSK;
6652 6739
6653 while ((cmd = next_cmd(&buf))) { 6740 while ((cmd = next_cmd(&buf))) {
6654 if (strlencmp(cmd, "up") == 0) { 6741 if (!tp_features.mixer_no_level_control) {
6655 if (new_mute) 6742 if (strlencmp(cmd, "up") == 0) {
6656 new_mute = 0; 6743 if (new_mute)
6657 else if (new_level < TP_EC_VOLUME_MAX) 6744 new_mute = 0;
6658 new_level++; 6745 else if (new_level < TP_EC_VOLUME_MAX)
6659 } else if (strlencmp(cmd, "down") == 0) { 6746 new_level++;
6660 if (new_mute) 6747 continue;
6661 new_mute = 0; 6748 } else if (strlencmp(cmd, "down") == 0) {
6662 else if (new_level > 0) 6749 if (new_mute)
6663 new_level--; 6750 new_mute = 0;
6664 } else if (sscanf(cmd, "level %u", &l) == 1 && 6751 else if (new_level > 0)
6665 l >= 0 && l <= TP_EC_VOLUME_MAX) { 6752 new_level--;
6666 new_level = l; 6753 continue;
6667 } else if (strlencmp(cmd, "mute") == 0) { 6754 } else if (sscanf(cmd, "level %u", &l) == 1 &&
6755 l >= 0 && l <= TP_EC_VOLUME_MAX) {
6756 new_level = l;
6757 continue;
6758 }
6759 }
6760 if (strlencmp(cmd, "mute") == 0)
6668 new_mute = TP_EC_AUDIO_MUTESW_MSK; 6761 new_mute = TP_EC_AUDIO_MUTESW_MSK;
6669 } else 6762 else if (strlencmp(cmd, "unmute") == 0)
6763 new_mute = 0;
6764 else
6670 return -EINVAL; 6765 return -EINVAL;
6671 } 6766 }
6672 6767
6673 tpacpi_disclose_usertask("procfs volume", 6768 if (tp_features.mixer_no_level_control) {
6674 "%smute and set level to %d\n", 6769 tpacpi_disclose_usertask("procfs volume", "%smute\n",
6675 new_mute ? "" : "un", new_level); 6770 new_mute ? "" : "un");
6676 6771 rc = volume_set_mute(!!new_mute);
6677 rc = volume_set_status(new_mute | new_level); 6772 } else {
6773 tpacpi_disclose_usertask("procfs volume",
6774 "%smute and set level to %d\n",
6775 new_mute ? "" : "un", new_level);
6776 rc = volume_set_status(new_mute | new_level);
6777 }
6678 6778
6679 return (rc == -EINTR) ? -ERESTARTSYS : rc; 6779 return (rc == -EINTR) ? -ERESTARTSYS : rc;
6680} 6780}
@@ -8410,6 +8510,11 @@ MODULE_PARM_DESC(volume_mode,
8410 "Selects volume control strategy: " 8510 "Selects volume control strategy: "
8411 "0=auto, 1=EC, 2=N/A, 3=EC+NVRAM"); 8511 "0=auto, 1=EC, 2=N/A, 3=EC+NVRAM");
8412 8512
8513module_param_named(volume_capabilities, volume_capabilities, uint, 0444);
8514MODULE_PARM_DESC(volume_capabilities,
8515 "Selects the mixer capabilites: "
8516 "0=auto, 1=volume and mute, 2=mute only");
8517
8413#define TPACPI_PARAM(feature) \ 8518#define TPACPI_PARAM(feature) \
8414 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ 8519 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
8415 MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ 8520 MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \