aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt19
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c159
2 files changed, 149 insertions, 29 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 96687d0106a..bd87682103c 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -1098,18 +1098,31 @@ Volume control
1098procfs: /proc/acpi/ibm/volume 1098procfs: /proc/acpi/ibm/volume
1099 1099
1100This feature allows volume control on ThinkPad models with a digital 1100This feature allows volume control on ThinkPad models with a digital
1101volume knob, as well as mute/unmute control. The available commands are: 1101volume knob (when available, not all models have it), as well as
1102mute/unmute control. The available commands are:
1102 1103
1103 echo up >/proc/acpi/ibm/volume 1104 echo up >/proc/acpi/ibm/volume
1104 echo down >/proc/acpi/ibm/volume 1105 echo down >/proc/acpi/ibm/volume
1105 echo mute >/proc/acpi/ibm/volume 1106 echo mute >/proc/acpi/ibm/volume
1107 echo unmute >/proc/acpi/ibm/volume
1106 echo 'level <level>' >/proc/acpi/ibm/volume 1108 echo 'level <level>' >/proc/acpi/ibm/volume
1107 1109
1108The <level> number range is 0 to 14 although not all of them may be 1110The <level> number range is 0 to 14 although not all of them may be
1109distinct. The unmute the volume after the mute command, use either the 1111distinct. The unmute the volume after the mute command, use either the
1110up or down command (the level command will not unmute the volume). 1112up or down command (the level command will not unmute the volume), or
1113the unmute command.
1114
1111The current volume level and mute state is shown in the file. 1115The current volume level and mute state is shown in the file.
1112 1116
1117You can use the volume_capabilities parameter to tell the driver
1118whether your thinkpad has volume control or mute-only control:
1119volume_capabilities=1 for mixers with mute and volume control,
1120volume_capabilities=2 for mixers with only mute control.
1121
1122If the driver misdetects the capabilities for your ThinkPad model,
1123please report this to ibm-acpi-devel@lists.sourceforge.net, so that we
1124can update the driver.
1125
1113There are two strategies for volume control. To select which one 1126There are two strategies for volume control. To select which one
1114should be used, use the volume_mode module parameter: volume_mode=1 1127should be used, use the volume_mode module parameter: volume_mode=1
1115selects EC mode, and volume_mode=3 selects EC mode with NVRAM backing 1128selects EC mode, and volume_mode=3 selects EC mode with NVRAM backing
@@ -1450,3 +1463,5 @@ Sysfs interface changelog:
1450 is deprecated and marked for removal. 1463 is deprecated and marked for removal.
1451 1464
14520x020600: Marker for backlight change event support. 14650x020600: Marker for backlight change event support.
1466
14670x020700: Support for mute-only mixers.
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a2f5312c6a4..4d909d5a034 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 " \