aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2009-12-15 18:51:09 -0500
committerLen Brown <len.brown@intel.com>2009-12-15 23:57:26 -0500
commita112ceee673629afc204bf6b4a4828a6143a083f (patch)
tree688f07e2ba0dd22dffb265dbb3b9bdbc818bc5a5 /drivers/platform
parent329e4e18dfdc552f36b0642a3de5ebfa96063666 (diff)
thinkpad-acpi: support MUTE-only ThinkPads
Lenovo removed the extra mixer since the T61 and thereabouts. Newer Lenovo models only have the mute gate function, and leave the volume control to the HDA mixer. Until a way to automatically query the firmware about its audio control capabilities is discovered (there might not be any), use a white/black list. We will likely need to ask T60 (old and new model) and Z60/Z61 users whether they have volume control to populate the black/white list. Meanwhile, provide a volume_capabilities parameter that can be used to override the defaults. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Cc: Lorne Applebaum <lorne.applebaum@gmail.com> Cc: Matthew Garrett <mjg@redhat.com> Signed-off-by: Len Brown <len.brown@intel.com>
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 " \