aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig28
-rw-r--r--drivers/platform/x86/dell-wmi.c18
-rw-r--r--drivers/platform/x86/hp-wmi.c9
-rw-r--r--drivers/platform/x86/msi-wmi.c9
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c59
-rw-r--r--drivers/platform/x86/wmi.c36
6 files changed, 131 insertions, 28 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index ec4faffe6b05..db32c25e3605 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -231,8 +231,36 @@ config THINKPAD_ACPI
231 231
232 This driver was formerly known as ibm-acpi. 232 This driver was formerly known as ibm-acpi.
233 233
234 Extra functionality will be available if the rfkill (CONFIG_RFKILL)
235 and/or ALSA (CONFIG_SND) subsystems are available in the kernel.
236 Note that if you want ThinkPad-ACPI to be built-in instead of
237 modular, ALSA and rfkill will also have to be built-in.
238
234 If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. 239 If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
235 240
241config THINKPAD_ACPI_ALSA_SUPPORT
242 bool "Console audio control ALSA interface"
243 depends on THINKPAD_ACPI
244 depends on SND
245 depends on SND = y || THINKPAD_ACPI = SND
246 default y
247 ---help---
248 Enables monitoring of the built-in console audio output control
249 (headphone and speakers), which is operated by the mute and (in
250 some ThinkPad models) volume hotkeys.
251
252 If this option is enabled, ThinkPad-ACPI will export an ALSA card
253 with a single read-only mixer control, which should be used for
254 on-screen-display feedback purposes by the Desktop Environment.
255
256 Optionally, the driver will also allow software control (the
257 ALSA mixer will be made read-write). Please refer to the driver
258 documentation for details.
259
260 All IBM models have both volume and mute control. Newer Lenovo
261 models only have mute control (the volume hotkeys are just normal
262 keys and volume control is done through the main HDA mixer).
263
236config THINKPAD_ACPI_DEBUGFACILITIES 264config THINKPAD_ACPI_DEBUGFACILITIES
237 bool "Maintainer debug facilities" 265 bool "Maintainer debug facilities"
238 depends on THINKPAD_ACPI 266 depends on THINKPAD_ACPI
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 916ccb2b316c..1b1dddbd5744 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -202,8 +202,13 @@ static void dell_wmi_notify(u32 value, void *context)
202 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 202 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
203 static struct key_entry *key; 203 static struct key_entry *key;
204 union acpi_object *obj; 204 union acpi_object *obj;
205 acpi_status status;
205 206
206 wmi_get_event_data(value, &response); 207 status = wmi_get_event_data(value, &response);
208 if (status != AE_OK) {
209 printk(KERN_INFO "dell-wmi: bad event status 0x%x\n", status);
210 return;
211 }
207 212
208 obj = (union acpi_object *)response.pointer; 213 obj = (union acpi_object *)response.pointer;
209 214
@@ -323,8 +328,9 @@ static int __init dell_wmi_input_setup(void)
323static int __init dell_wmi_init(void) 328static int __init dell_wmi_init(void)
324{ 329{
325 int err; 330 int err;
331 acpi_status status;
326 332
327 if (wmi_has_guid(DELL_EVENT_GUID)) { 333 if (!wmi_has_guid(DELL_EVENT_GUID)) {
328 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); 334 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
329 return -ENODEV; 335 return -ENODEV;
330 } 336 }
@@ -336,14 +342,14 @@ static int __init dell_wmi_init(void)
336 if (err) 342 if (err)
337 return err; 343 return err;
338 344
339 err = wmi_install_notify_handler(DELL_EVENT_GUID, 345 status = wmi_install_notify_handler(DELL_EVENT_GUID,
340 dell_wmi_notify, NULL); 346 dell_wmi_notify, NULL);
341 if (err) { 347 if (ACPI_FAILURE(status)) {
342 input_unregister_device(dell_wmi_input_dev); 348 input_unregister_device(dell_wmi_input_dev);
343 printk(KERN_ERR 349 printk(KERN_ERR
344 "dell-wmi: Unable to register notify handler - %d\n", 350 "dell-wmi: Unable to register notify handler - %d\n",
345 err); 351 status);
346 return err; 352 return -ENODEV;
347 } 353 }
348 354
349 return 0; 355 return 0;
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 8781d8fa7a57..5b648f0c6075 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -338,8 +338,13 @@ static void hp_wmi_notify(u32 value, void *context)
338 static struct key_entry *key; 338 static struct key_entry *key;
339 union acpi_object *obj; 339 union acpi_object *obj;
340 int eventcode; 340 int eventcode;
341 acpi_status status;
341 342
342 wmi_get_event_data(value, &response); 343 status = wmi_get_event_data(value, &response);
344 if (status != AE_OK) {
345 printk(KERN_INFO "hp-wmi: bad event status 0x%x\n", status);
346 return;
347 }
343 348
344 obj = (union acpi_object *)response.pointer; 349 obj = (union acpi_object *)response.pointer;
345 350
@@ -581,7 +586,7 @@ static int __init hp_wmi_init(void)
581 if (wmi_has_guid(HPWMI_EVENT_GUID)) { 586 if (wmi_has_guid(HPWMI_EVENT_GUID)) {
582 err = wmi_install_notify_handler(HPWMI_EVENT_GUID, 587 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
583 hp_wmi_notify, NULL); 588 hp_wmi_notify, NULL);
584 if (!err) 589 if (ACPI_SUCCESS(err))
585 hp_wmi_input_setup(); 590 hp_wmi_input_setup();
586 } 591 }
587 592
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index 7f77f908bb01..f5f70d4c6913 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -149,8 +149,13 @@ static void msi_wmi_notify(u32 value, void *context)
149 static struct key_entry *key; 149 static struct key_entry *key;
150 union acpi_object *obj; 150 union acpi_object *obj;
151 ktime_t cur; 151 ktime_t cur;
152 acpi_status status;
152 153
153 wmi_get_event_data(value, &response); 154 status = wmi_get_event_data(value, &response);
155 if (status != AE_OK) {
156 printk(KERN_INFO DRV_PFX "bad event status 0x%x\n", status);
157 return;
158 }
154 159
155 obj = (union acpi_object *)response.pointer; 160 obj = (union acpi_object *)response.pointer;
156 161
@@ -236,7 +241,7 @@ static int __init msi_wmi_init(void)
236 } 241 }
237 err = wmi_install_notify_handler(MSIWMI_EVENT_GUID, 242 err = wmi_install_notify_handler(MSIWMI_EVENT_GUID,
238 msi_wmi_notify, NULL); 243 msi_wmi_notify, NULL);
239 if (err) 244 if (ACPI_FAILURE(err))
240 return -EINVAL; 245 return -EINVAL;
241 246
242 err = msi_wmi_input_setup(); 247 err = msi_wmi_input_setup();
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 448c8aeb166b..e67e4feb35cb 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6384,11 +6384,13 @@ static struct ibm_struct brightness_driver_data = {
6384 * and we leave them unchanged. 6384 * and we leave them unchanged.
6385 */ 6385 */
6386 6386
6387#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
6388
6387#define TPACPI_ALSA_DRVNAME "ThinkPad EC" 6389#define TPACPI_ALSA_DRVNAME "ThinkPad EC"
6388#define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control" 6390#define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control"
6389#define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME 6391#define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME
6390 6392
6391static int alsa_index = SNDRV_DEFAULT_IDX1; 6393static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */
6392static char *alsa_id = "ThinkPadEC"; 6394static char *alsa_id = "ThinkPadEC";
6393static int alsa_enable = SNDRV_DEFAULT_ENABLE1; 6395static int alsa_enable = SNDRV_DEFAULT_ENABLE1;
6394 6396
@@ -6705,10 +6707,11 @@ static int __init volume_create_alsa_mixer(void)
6705 6707
6706 rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE, 6708 rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
6707 sizeof(struct tpacpi_alsa_data), &card); 6709 sizeof(struct tpacpi_alsa_data), &card);
6708 if (rc < 0) 6710 if (rc < 0 || !card) {
6709 return rc; 6711 printk(TPACPI_ERR
6710 if (!card) 6712 "Failed to create ALSA card structures: %d\n", rc);
6711 return -ENOMEM; 6713 return 1;
6714 }
6712 6715
6713 BUG_ON(!card->private_data); 6716 BUG_ON(!card->private_data);
6714 data = card->private_data; 6717 data = card->private_data;
@@ -6741,8 +6744,9 @@ static int __init volume_create_alsa_mixer(void)
6741 rc = snd_ctl_add(card, ctl_vol); 6744 rc = snd_ctl_add(card, ctl_vol);
6742 if (rc < 0) { 6745 if (rc < 0) {
6743 printk(TPACPI_ERR 6746 printk(TPACPI_ERR
6744 "Failed to create ALSA volume control\n"); 6747 "Failed to create ALSA volume control: %d\n",
6745 goto err_out; 6748 rc);
6749 goto err_exit;
6746 } 6750 }
6747 data->ctl_vol_id = &ctl_vol->id; 6751 data->ctl_vol_id = &ctl_vol->id;
6748 } 6752 }
@@ -6750,22 +6754,25 @@ static int __init volume_create_alsa_mixer(void)
6750 ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL); 6754 ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL);
6751 rc = snd_ctl_add(card, ctl_mute); 6755 rc = snd_ctl_add(card, ctl_mute);
6752 if (rc < 0) { 6756 if (rc < 0) {
6753 printk(TPACPI_ERR "Failed to create ALSA mute control\n"); 6757 printk(TPACPI_ERR "Failed to create ALSA mute control: %d\n",
6754 goto err_out; 6758 rc);
6759 goto err_exit;
6755 } 6760 }
6756 data->ctl_mute_id = &ctl_mute->id; 6761 data->ctl_mute_id = &ctl_mute->id;
6757 6762
6758 snd_card_set_dev(card, &tpacpi_pdev->dev); 6763 snd_card_set_dev(card, &tpacpi_pdev->dev);
6759 rc = snd_card_register(card); 6764 rc = snd_card_register(card);
6760
6761err_out:
6762 if (rc < 0) { 6765 if (rc < 0) {
6763 snd_card_free(card); 6766 printk(TPACPI_ERR "Failed to register ALSA card: %d\n", rc);
6764 card = NULL; 6767 goto err_exit;
6765 } 6768 }
6766 6769
6767 alsa_card = card; 6770 alsa_card = card;
6768 return rc; 6771 return 0;
6772
6773err_exit:
6774 snd_card_free(card);
6775 return 1;
6769} 6776}
6770 6777
6771#define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */ 6778#define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */
@@ -7016,6 +7023,28 @@ static struct ibm_struct volume_driver_data = {
7016 .shutdown = volume_shutdown, 7023 .shutdown = volume_shutdown,
7017}; 7024};
7018 7025
7026#else /* !CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
7027
7028#define alsa_card NULL
7029
7030static void inline volume_alsa_notify_change(void)
7031{
7032}
7033
7034static int __init volume_init(struct ibm_init_struct *iibm)
7035{
7036 printk(TPACPI_INFO
7037 "volume: disabled as there is no ALSA support in this kernel\n");
7038
7039 return 1;
7040}
7041
7042static struct ibm_struct volume_driver_data = {
7043 .name = "volume",
7044};
7045
7046#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
7047
7019/************************************************************************* 7048/*************************************************************************
7020 * Fan subdriver 7049 * Fan subdriver
7021 */ 7050 */
@@ -8738,6 +8767,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
8738 "used for backwards compatibility with userspace, " 8767 "used for backwards compatibility with userspace, "
8739 "see documentation"); 8768 "see documentation");
8740 8769
8770#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
8741module_param_named(volume_mode, volume_mode, uint, 0444); 8771module_param_named(volume_mode, volume_mode, uint, 0444);
8742MODULE_PARM_DESC(volume_mode, 8772MODULE_PARM_DESC(volume_mode,
8743 "Selects volume control strategy: " 8773 "Selects volume control strategy: "
@@ -8760,6 +8790,7 @@ module_param_named(id, alsa_id, charp, 0444);
8760MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer"); 8790MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer");
8761module_param_named(enable, alsa_enable, bool, 0444); 8791module_param_named(enable, alsa_enable, bool, 0444);
8762MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer"); 8792MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer");
8793#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
8763 8794
8764#define TPACPI_PARAM(feature) \ 8795#define TPACPI_PARAM(feature) \
8765 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ 8796 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 9f93d6c0f510..b104302fea0a 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -492,8 +492,7 @@ wmi_notify_handler handler, void *data)
492 if (!guid || !handler) 492 if (!guid || !handler)
493 return AE_BAD_PARAMETER; 493 return AE_BAD_PARAMETER;
494 494
495 find_guid(guid, &block); 495 if (!find_guid(guid, &block))
496 if (!block)
497 return AE_NOT_EXIST; 496 return AE_NOT_EXIST;
498 497
499 if (block->handler) 498 if (block->handler)
@@ -521,8 +520,7 @@ acpi_status wmi_remove_notify_handler(const char *guid)
521 if (!guid) 520 if (!guid)
522 return AE_BAD_PARAMETER; 521 return AE_BAD_PARAMETER;
523 522
524 find_guid(guid, &block); 523 if (!find_guid(guid, &block))
525 if (!block)
526 return AE_NOT_EXIST; 524 return AE_NOT_EXIST;
527 525
528 if (!block->handler) 526 if (!block->handler)
@@ -716,6 +714,22 @@ static int wmi_class_init(void)
716 return ret; 714 return ret;
717} 715}
718 716
717static bool guid_already_parsed(const char *guid_string)
718{
719 struct guid_block *gblock;
720 struct wmi_block *wblock;
721 struct list_head *p;
722
723 list_for_each(p, &wmi_blocks.list) {
724 wblock = list_entry(p, struct wmi_block, list);
725 gblock = &wblock->gblock;
726
727 if (strncmp(gblock->guid, guid_string, 16) == 0)
728 return true;
729 }
730 return false;
731}
732
719/* 733/*
720 * Parse the _WDG method for the GUID data blocks 734 * Parse the _WDG method for the GUID data blocks
721 */ 735 */
@@ -725,6 +739,7 @@ static __init acpi_status parse_wdg(acpi_handle handle)
725 union acpi_object *obj; 739 union acpi_object *obj;
726 struct guid_block *gblock; 740 struct guid_block *gblock;
727 struct wmi_block *wblock; 741 struct wmi_block *wblock;
742 char guid_string[37];
728 acpi_status status; 743 acpi_status status;
729 u32 i, total; 744 u32 i, total;
730 745
@@ -747,6 +762,19 @@ static __init acpi_status parse_wdg(acpi_handle handle)
747 memcpy(gblock, obj->buffer.pointer, obj->buffer.length); 762 memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
748 763
749 for (i = 0; i < total; i++) { 764 for (i = 0; i < total; i++) {
765 /*
766 Some WMI devices, like those for nVidia hooks, have a
767 duplicate GUID. It's not clear what we should do in this
768 case yet, so for now, we'll just ignore the duplicate.
769 Anyone who wants to add support for that device can come
770 up with a better workaround for the mess then.
771 */
772 if (guid_already_parsed(gblock[i].guid) == true) {
773 wmi_gtoa(gblock[i].guid, guid_string);
774 printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
775 guid_string);
776 continue;
777 }
750 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); 778 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
751 if (!wblock) 779 if (!wblock)
752 return AE_NO_MEMORY; 780 return AE_NO_MEMORY;