Commit 08d869aa authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6:
  ACPI: introduce kernel parameter acpi_sleep=sci_force_enable
  ACPI: WMI: Survive BIOS with duplicate GUIDs
  dell-wmi - fix condition to abort driver loading
  wmi: check find_guid() return value to prevent oops
  dell-wmi, hp-wmi, msi-wmi: check wmi_get_event_data() return value
  ACPI: hp-wmi, msi-wmi: clarify that wmi_install_notify_handler() returns an acpi_status
  dell-wmi: sys_init_module: 'dell_wmi'->init suspiciously returned 21, it should
  ACPI video: correct error-handling code
  ACPI video: no warning message if "acpi_backlight=vendor" is used
  ACPI: fix ACPI=n allmodconfig build
  thinkpad-acpi: improve Kconfig help text
  thinkpad-acpi: update volume subdriver documentation
  thinkpad-acpi: make volume subdriver optional
  thinkpad-acpi: don't fail to load the entire module due to ALSA problems
  thinkpad-acpi: don't take the first ALSA slot by default
parents 05a62548 1201b2a9
......@@ -240,7 +240,7 @@ and is between 256 and 4096 characters. It is defined in the file
acpi_sleep= [HW,ACPI] Sleep options
Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig,
old_ordering, s4_nonvs }
old_ordering, s4_nonvs, sci_force_enable }
See Documentation/power/video.txt for information on
s3_bios and s3_mode.
s3_beep is for debugging; it makes the PC's speaker beep
......@@ -253,6 +253,9 @@ and is between 256 and 4096 characters. It is defined in the file
of _PTS is used by default).
s4_nonvs prevents the kernel from saving/restoring the
ACPI NVS memory during hibernation.
sci_force_enable causes the kernel to set SCI_EN directly
on resume from S1/S3 (which is against the ACPI spec,
but some broken systems don't work without it).
acpi_use_timer_override [HW,ACPI]
Use timer override. For some broken Nvidia NF5 boards
......
......@@ -1092,8 +1092,8 @@ WARNING:
its level up and down at every change.
Volume control
--------------
Volume control (Console Audio control)
--------------------------------------
procfs: /proc/acpi/ibm/volume
ALSA: "ThinkPad Console Audio Control", default ID: "ThinkPadEC"
......@@ -1110,9 +1110,53 @@ the desktop environment to just provide on-screen-display feedback.
Software volume control should be done only in the main AC97/HDA
mixer.
This feature allows volume control on ThinkPad models with a digital
volume knob (when available, not all models have it), as well as
mute/unmute control. The available commands are:
About the ThinkPad Console Audio control:
ThinkPads have a built-in amplifier and muting circuit that drives the
console headphone and speakers. This circuit is after the main AC97
or HDA mixer in the audio path, and under exclusive control of the
firmware.
ThinkPads have three special hotkeys to interact with the console
audio control: volume up, volume down and mute.
It is worth noting that the normal way the mute function works (on
ThinkPads that do not have a "mute LED") is:
1. Press mute to mute. It will *always* mute, you can press it as
many times as you want, and the sound will remain mute.
2. Press either volume key to unmute the ThinkPad (it will _not_
change the volume, it will just unmute).
This is a very superior design when compared to the cheap software-only
mute-toggle solution found on normal consumer laptops: you can be
absolutely sure the ThinkPad will not make noise if you press the mute
button, no matter the previous state.
The IBM ThinkPads, and the earlier Lenovo ThinkPads have variable-gain
amplifiers driving the speakers and headphone output, and the firmware
also handles volume control for the headphone and speakers on these
ThinkPads without any help from the operating system (this volume
control stage exists after the main AC97 or HDA mixer in the audio
path).
The newer Lenovo models only have firmware mute control, and depend on
the main HDA mixer to do volume control (which is done by the operating
system). In this case, the volume keys are filtered out for unmute
key press (there are some firmware bugs in this area) and delivered as
normal key presses to the operating system (thinkpad-acpi is not
involved).
The ThinkPad-ACPI volume control:
The preferred way to interact with the Console Audio control is the
ALSA interface.
The legacy procfs interface allows one to read the current state,
and if volume control is enabled, accepts the following commands:
echo up >/proc/acpi/ibm/volume
echo down >/proc/acpi/ibm/volume
......@@ -1121,12 +1165,10 @@ mute/unmute control. The available commands are:
echo 'level <level>' >/proc/acpi/ibm/volume
The <level> number range is 0 to 14 although not all of them may be
distinct. The unmute the volume after the mute command, use either the
distinct. To unmute the volume after the mute command, use either the
up or down command (the level command will not unmute the volume), or
the unmute command.
The current volume level and mute state is shown in the file.
You can use the volume_capabilities parameter to tell the driver
whether your thinkpad has volume control or mute-only control:
volume_capabilities=1 for mixers with mute and volume control,
......
......@@ -162,6 +162,8 @@ static int __init acpi_sleep_setup(char *str)
#endif
if (strncmp(str, "old_ordering", 12) == 0)
acpi_old_suspend_ordering();
if (strncmp(str, "sci_force_enable", 16) == 0)
acpi_set_sci_en_on_resume();
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
......
......@@ -80,6 +80,23 @@ static int acpi_sleep_prepare(u32 acpi_state)
#ifdef CONFIG_ACPI_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
/*
* According to the ACPI specification the BIOS should make sure that ACPI is
* enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still,
* some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI
* on such systems during resume. Unfortunately that doesn't help in
* particularly pathological cases in which SCI_EN has to be set directly on
* resume, although the specification states very clearly that this flag is
* owned by the hardware. The set_sci_en_on_resume variable will be set in such
* cases.
*/
static bool set_sci_en_on_resume;
void __init acpi_set_sci_en_on_resume(void)
{
set_sci_en_on_resume = true;
}
/*
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
* user to request that behavior by using the 'acpi_old_suspend_ordering'
......@@ -170,18 +187,6 @@ static void acpi_pm_end(void)
#endif /* CONFIG_ACPI_SLEEP */
#ifdef CONFIG_SUSPEND
/*
* According to the ACPI specification the BIOS should make sure that ACPI is
* enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still,
* some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI
* on such systems during resume. Unfortunately that doesn't help in
* particularly pathological cases in which SCI_EN has to be set directly on
* resume, although the specification states very clearly that this flag is
* owned by the hardware. The set_sci_en_on_resume variable will be set in such
* cases.
*/
static bool set_sci_en_on_resume;
extern void do_suspend_lowlevel(void);
static u32 acpi_suspend_states[] = {
......
......@@ -999,8 +999,10 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
sprintf(name, "acpi_video%d", count++);
device->backlight = backlight_device_register(name,
NULL, device, &acpi_backlight_ops);
device->backlight->props.max_brightness = device->brightness->count-3;
kfree(name);
if (IS_ERR(device->backlight))
return;
device->backlight->props.max_brightness = device->brightness->count-3;
result = sysfs_create_link(&device->backlight->dev.kobj,
&device->dev->dev.kobj, "device");
......@@ -1979,6 +1981,10 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
unsigned long long level_current, level_next;
int result = -EINVAL;
/* no warning message if acpi_backlight=vendor is used */
if (!acpi_video_backlight_support())
return 0;
if (!device->brightness)
goto out;
......
......@@ -3204,7 +3204,7 @@ static __devinit int init_ipmi_si(void)
#ifdef CONFIG_ACPI
spmi_find_bmc();
#endif
#ifdef CONFIG_PNP
#ifdef CONFIG_ACPI
pnp_register_driver(&ipmi_pnp_driver);
#endif
......@@ -3330,7 +3330,7 @@ static __exit void cleanup_ipmi_si(void)
#ifdef CONFIG_PCI
pci_unregister_driver(&ipmi_pci_driver);
#endif
#ifdef CONFIG_PNP
#ifdef CONFIG_ACPI
pnp_unregister_driver(&ipmi_pnp_driver);
#endif
......
......@@ -231,8 +231,36 @@ config THINKPAD_ACPI
This driver was formerly known as ibm-acpi.
Extra functionality will be available if the rfkill (CONFIG_RFKILL)
and/or ALSA (CONFIG_SND) subsystems are available in the kernel.
Note that if you want ThinkPad-ACPI to be built-in instead of
modular, ALSA and rfkill will also have to be built-in.
If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
config THINKPAD_ACPI_ALSA_SUPPORT
bool "Console audio control ALSA interface"
depends on THINKPAD_ACPI
depends on SND
depends on SND = y || THINKPAD_ACPI = SND
default y
---help---
Enables monitoring of the built-in console audio output control
(headphone and speakers), which is operated by the mute and (in
some ThinkPad models) volume hotkeys.
If this option is enabled, ThinkPad-ACPI will export an ALSA card
with a single read-only mixer control, which should be used for
on-screen-display feedback purposes by the Desktop Environment.
Optionally, the driver will also allow software control (the
ALSA mixer will be made read-write). Please refer to the driver
documentation for details.
All IBM models have both volume and mute control. Newer Lenovo
models only have mute control (the volume hotkeys are just normal
keys and volume control is done through the main HDA mixer).
config THINKPAD_ACPI_DEBUGFACILITIES
bool "Maintainer debug facilities"
depends on THINKPAD_ACPI
......
......@@ -202,8 +202,13 @@ static void dell_wmi_notify(u32 value, void *context)
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
static struct key_entry *key;
union acpi_object *obj;
acpi_status status;
wmi_get_event_data(value, &response);
status = wmi_get_event_data(value, &response);
if (status != AE_OK) {
printk(KERN_INFO "dell-wmi: bad event status 0x%x\n", status);
return;
}
obj = (union acpi_object *)response.pointer;
......@@ -325,7 +330,7 @@ static int __init dell_wmi_init(void)
int err;
acpi_status status;
if (wmi_has_guid(DELL_EVENT_GUID)) {
if (!wmi_has_guid(DELL_EVENT_GUID)) {
printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
return -ENODEV;
}
......
......@@ -338,8 +338,13 @@ static void hp_wmi_notify(u32 value, void *context)
static struct key_entry *key;
union acpi_object *obj;
int eventcode;
acpi_status status;
wmi_get_event_data(value, &response);
status = wmi_get_event_data(value, &response);
if (status != AE_OK) {
printk(KERN_INFO "hp-wmi: bad event status 0x%x\n", status);
return;
}
obj = (union acpi_object *)response.pointer;
......@@ -581,7 +586,7 @@ static int __init hp_wmi_init(void)
if (wmi_has_guid(HPWMI_EVENT_GUID)) {
err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
hp_wmi_notify, NULL);
if (!err)
if (ACPI_SUCCESS(err))
hp_wmi_input_setup();
}
......
......@@ -149,8 +149,13 @@ static void msi_wmi_notify(u32 value, void *context)
static struct key_entry *key;
union acpi_object *obj;
ktime_t cur;
acpi_status status;
wmi_get_event_data(value, &response);
status = wmi_get_event_data(value, &response);
if (status != AE_OK) {
printk(KERN_INFO DRV_PFX "bad event status 0x%x\n", status);
return;
}
obj = (union acpi_object *)response.pointer;
......@@ -236,7 +241,7 @@ static int __init msi_wmi_init(void)
}
err = wmi_install_notify_handler(MSIWMI_EVENT_GUID,
msi_wmi_notify, NULL);
if (err)
if (ACPI_FAILURE(err))
return -EINVAL;
err = msi_wmi_input_setup();
......
......@@ -6384,11 +6384,13 @@ static struct ibm_struct brightness_driver_data = {
* and we leave them unchanged.
*/
#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
#define TPACPI_ALSA_DRVNAME "ThinkPad EC"
#define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control"
#define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME
static int alsa_index = SNDRV_DEFAULT_IDX1;
static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */
static char *alsa_id = "ThinkPadEC";
static int alsa_enable = SNDRV_DEFAULT_ENABLE1;
......@@ -6705,10 +6707,11 @@ static int __init volume_create_alsa_mixer(void)
rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
sizeof(struct tpacpi_alsa_data), &card);
if (rc < 0)
return rc;
if (!card)
return -ENOMEM;
if (rc < 0 || !card) {
printk(TPACPI_ERR
"Failed to create ALSA card structures: %d\n", rc);
return 1;
}
BUG_ON(!card->private_data);
data = card->private_data;
......@@ -6741,8 +6744,9 @@ static int __init volume_create_alsa_mixer(void)
rc = snd_ctl_add(card, ctl_vol);
if (rc < 0) {
printk(TPACPI_ERR
"Failed to create ALSA volume control\n");
goto err_out;
"Failed to create ALSA volume control: %d\n",
rc);
goto err_exit;
}
data->ctl_vol_id = &ctl_vol->id;
}
......@@ -6750,22 +6754,25 @@ static int __init volume_create_alsa_mixer(void)
ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL);
rc = snd_ctl_add(card, ctl_mute);
if (rc < 0) {
printk(TPACPI_ERR "Failed to create ALSA mute control\n");
goto err_out;
printk(TPACPI_ERR "Failed to create ALSA mute control: %d\n",
rc);
goto err_exit;
}
data->ctl_mute_id = &ctl_mute->id;
snd_card_set_dev(card, &tpacpi_pdev->dev);
rc = snd_card_register(card);
err_out:
if (rc < 0) {
snd_card_free(card);
card = NULL;
printk(TPACPI_ERR "Failed to register ALSA card: %d\n", rc);
goto err_exit;
}
alsa_card = card;
return rc;
return 0;
err_exit:
snd_card_free(card);
return 1;
}
#define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */
......@@ -7016,6 +7023,28 @@ static struct ibm_struct volume_driver_data = {
.shutdown = volume_shutdown,
};
#else /* !CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
#define alsa_card NULL
static void inline volume_alsa_notify_change(void)
{
}
static int __init volume_init(struct ibm_init_struct *iibm)
{
printk(TPACPI_INFO
"volume: disabled as there is no ALSA support in this kernel\n");
return 1;
}
static struct ibm_struct volume_driver_data = {
.name = "volume",
};
#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
/*************************************************************************
* Fan subdriver
*/
......@@ -8738,6 +8767,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
"used for backwards compatibility with userspace, "
"see documentation");
#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
module_param_named(volume_mode, volume_mode, uint, 0444);
MODULE_PARM_DESC(volume_mode,
"Selects volume control strategy: "
......@@ -8760,6 +8790,7 @@ module_param_named(id, alsa_id, charp, 0444);
MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer");
module_param_named(enable, alsa_enable, bool, 0444);
MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer");
#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
#define TPACPI_PARAM(feature) \
module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
......
......@@ -714,6 +714,22 @@ static int wmi_class_init(void)
return ret;
}
static bool guid_already_parsed(const char *guid_string)
{
struct guid_block *gblock;
struct wmi_block *wblock;
struct list_head *p;
list_for_each(p, &wmi_blocks.list) {
wblock = list_entry(p, struct wmi_block, list);
gblock = &wblock->gblock;
if (strncmp(gblock->guid, guid_string, 16) == 0)
return true;
}
return false;
}
/*
* Parse the _WDG method for the GUID data blocks
*/
......@@ -723,6 +739,7 @@ static __init acpi_status parse_wdg(acpi_handle handle)
union acpi_object *obj;
struct guid_block *gblock;
struct wmi_block *wblock;
char guid_string[37];
acpi_status status;
u32 i, total;
......@@ -745,6 +762,19 @@ static __init acpi_status parse_wdg(acpi_handle handle)
memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
for (i = 0; i < total; i++) {
/*
Some WMI devices, like those for nVidia hooks, have a
duplicate GUID. It's not clear what we should do in this
case yet, so for now, we'll just ignore the duplicate.
Anyone who wants to add support for that device can come
up with a better workaround for the mess then.
*/
if (guid_already_parsed(gblock[i].guid) == true) {
wmi_gtoa(gblock[i].guid, guid_string);
printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
guid_string);
continue;
}
wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
if (!wblock)
return AE_NO_MEMORY;
......
......@@ -251,6 +251,7 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,
void __init acpi_no_s4_hw_signature(void);
void __init acpi_old_suspend_ordering(void);
void __init acpi_s4_no_nvs(void);
void __init acpi_set_sci_en_on_resume(void);
#endif /* CONFIG_PM_SLEEP */
struct acpi_osc_context {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment