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: (39 commits) ACPI: EC: Workaround for optimized controllers (version 3) ACPI: EC: use printk_ratelimit(), add some DEBUG mode messages Revert "ACPI: EC: Workaround for optimized controllers" ACPI: fix two IRQ8 issues in IOAPIC mode ACPI: Add missing spaces to printk format cpuidle: fix HP nx6125 regression cpuidle: add sched_clock_idle_[sleep|wakeup]_event() hooks cpuidle: fix C3 for no bus-master control case ACPI: thinkpad-acpi: fix oops when a module parameter has no value Revert "Fix very high interrupt rate for IRQ8 (rtc) unless pnpacpi=off" ACPI: EC: Don't init EC early if it has no _INI Revert "acpi: make ACPI_PROCFS default to y" Revert "ACPI: add documentation for deprecated /proc/acpi/battery in ACPI_PROCFS" ACPI: Split out control for /proc/acpi entries from battery, ac, and sbs. ACPI: Video: Increase buffer size for writes to brightness proc file. ACPI: EC: Workaround for optimized controllers ACPI: SBS: Fix retval warning ACPI: Enable MSR (FixedHW) support for T-States ACPI: Get throttling info from BIOS only after evaluating _PDC ACPI: Use _TSS for throttling control, when present. Add error checks. ...
This commit is contained in:
commit
6b41016032
24 changed files with 810 additions and 379 deletions
|
@ -1,7 +1,7 @@
|
|||
ThinkPad ACPI Extras Driver
|
||||
|
||||
Version 0.16
|
||||
August 2nd, 2007
|
||||
Version 0.17
|
||||
October 04th, 2007
|
||||
|
||||
Borislav Deianov <borislav@users.sf.net>
|
||||
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
|
||||
|
@ -923,19 +923,34 @@ sysfs backlight device "thinkpad_screen"
|
|||
This feature allows software control of the LCD brightness on ThinkPad
|
||||
models which don't have a hardware brightness slider.
|
||||
|
||||
It has some limitations: the LCD backlight cannot be actually turned on or off
|
||||
by this interface, and in many ThinkPad models, the "dim while on battery"
|
||||
functionality will be enabled by the BIOS when this interface is used, and
|
||||
cannot be controlled.
|
||||
It has some limitations: the LCD backlight cannot be actually turned on or
|
||||
off by this interface, and in many ThinkPad models, the "dim while on
|
||||
battery" functionality will be enabled by the BIOS when this interface is
|
||||
used, and cannot be controlled.
|
||||
|
||||
The backlight control has eight levels, ranging from 0 to 7. Some of the
|
||||
levels may not be distinct.
|
||||
On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control
|
||||
has eight brightness levels, ranging from 0 to 7. Some of the levels
|
||||
may not be distinct. Later Lenovo models that implement the ACPI
|
||||
display backlight brightness control methods have 16 levels, ranging
|
||||
from 0 to 15.
|
||||
|
||||
There are two interfaces to the firmware for brightness control, EC and CMOS.
|
||||
To select which one should be used, use the brightness_mode module parameter:
|
||||
brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
|
||||
brightness_mode=3 selects both EC and CMOS. The driver tries to autodetect
|
||||
which interface to use.
|
||||
There are two interfaces to the firmware for direct brightness control,
|
||||
EC and CMOS. To select which one should be used, use the
|
||||
brightness_mode module parameter: brightness_mode=1 selects EC mode,
|
||||
brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC
|
||||
and CMOS. The driver tries to autodetect which interface to use.
|
||||
|
||||
When display backlight brightness controls are available through the
|
||||
standard ACPI interface, it is best to use it instead of this direct
|
||||
ThinkPad-specific interface. The driver will disable its native
|
||||
backlight brightness control interface if it detects that the standard
|
||||
ACPI interface is available in the ThinkPad.
|
||||
|
||||
The brightness_enable module parameter can be used to control whether
|
||||
the LCD brightness control feature will be enabled when available.
|
||||
brightness_enable=0 forces it to be disabled. brightness_enable=1
|
||||
forces it to be enabled when available, even if the standard ACPI
|
||||
interface is also available.
|
||||
|
||||
Procfs notes:
|
||||
|
||||
|
@ -947,11 +962,11 @@ Procfs notes:
|
|||
|
||||
Sysfs notes:
|
||||
|
||||
The interface is implemented through the backlight sysfs class, which is poorly
|
||||
documented at this time.
|
||||
The interface is implemented through the backlight sysfs class, which is
|
||||
poorly documented at this time.
|
||||
|
||||
Locate the thinkpad_screen device under /sys/class/backlight, and inside it
|
||||
there will be the following attributes:
|
||||
Locate the thinkpad_screen device under /sys/class/backlight, and inside
|
||||
it there will be the following attributes:
|
||||
|
||||
max_brightness:
|
||||
Reads the maximum brightness the hardware can be set to.
|
||||
|
@ -961,17 +976,19 @@ there will be the following attributes:
|
|||
Reads what brightness the screen is set to at this instant.
|
||||
|
||||
brightness:
|
||||
Writes request the driver to change brightness to the given
|
||||
value. Reads will tell you what brightness the driver is trying
|
||||
to set the display to when "power" is set to zero and the display
|
||||
has not been dimmed by a kernel power management event.
|
||||
Writes request the driver to change brightness to the
|
||||
given value. Reads will tell you what brightness the
|
||||
driver is trying to set the display to when "power" is set
|
||||
to zero and the display has not been dimmed by a kernel
|
||||
power management event.
|
||||
|
||||
power:
|
||||
power management mode, where 0 is "display on", and 1 to 3 will
|
||||
dim the display backlight to brightness level 0 because
|
||||
thinkpad-acpi cannot really turn the backlight off. Kernel
|
||||
power management events can temporarily increase the current
|
||||
power management level, i.e. they can dim the display.
|
||||
power management mode, where 0 is "display on", and 1 to 3
|
||||
will dim the display backlight to brightness level 0
|
||||
because thinkpad-acpi cannot really turn the backlight
|
||||
off. Kernel power management events can temporarily
|
||||
increase the current power management level, i.e. they can
|
||||
dim the display.
|
||||
|
||||
|
||||
Volume control -- /proc/acpi/ibm/volume
|
||||
|
|
|
@ -49,6 +49,9 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
|
|||
if (cpu_has(c, X86_FEATURE_EST))
|
||||
buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP;
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_ACPI))
|
||||
buf[2] |= ACPI_PDC_T_FFH;
|
||||
|
||||
obj->type = ACPI_TYPE_BUFFER;
|
||||
obj->buffer.length = 12;
|
||||
obj->buffer.pointer = (u8 *) buf;
|
||||
|
|
|
@ -115,6 +115,3 @@ static int __init acpi_sleep_setup(char *str)
|
|||
|
||||
__setup("acpi_sleep=", acpi_sleep_setup);
|
||||
|
||||
void acpi_pci_link_exit(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -962,7 +962,7 @@ static int EISA_ELCR(unsigned int irq)
|
|||
#define default_MCA_trigger(idx) (1)
|
||||
#define default_MCA_polarity(idx) (0)
|
||||
|
||||
static int __init MPBIOS_polarity(int idx)
|
||||
static int MPBIOS_polarity(int idx)
|
||||
{
|
||||
int bus = mp_irqs[idx].mpc_srcbus;
|
||||
int polarity;
|
||||
|
@ -2830,6 +2830,25 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
|
|||
return 0;
|
||||
}
|
||||
|
||||
int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (skip_ioapic_setup)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < mp_irq_entries; i++)
|
||||
if (mp_irqs[i].mpc_irqtype == mp_INT &&
|
||||
mp_irqs[i].mpc_srcbusirq == bus_irq)
|
||||
break;
|
||||
if (i >= mp_irq_entries)
|
||||
return -1;
|
||||
|
||||
*trigger = irq_trigger(i);
|
||||
*polarity = irq_polarity(i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static int __init parse_disable_timer_pin_1(char *arg)
|
||||
|
|
|
@ -546,7 +546,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
|
|||
#define default_PCI_trigger(idx) (1)
|
||||
#define default_PCI_polarity(idx) (1)
|
||||
|
||||
static int __init MPBIOS_polarity(int idx)
|
||||
static int MPBIOS_polarity(int idx)
|
||||
{
|
||||
int bus = mp_irqs[idx].mpc_srcbus;
|
||||
int polarity;
|
||||
|
@ -2222,8 +2222,27 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (skip_ioapic_setup)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < mp_irq_entries; i++)
|
||||
if (mp_irqs[i].mpc_irqtype == mp_INT &&
|
||||
mp_irqs[i].mpc_srcbusirq == bus_irq)
|
||||
break;
|
||||
if (i >= mp_irq_entries)
|
||||
return -1;
|
||||
|
||||
*trigger = irq_trigger(i);
|
||||
*polarity = irq_polarity(i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
/*
|
||||
* This function currently is only a helper for the i386 smp boot process where
|
||||
|
@ -2260,3 +2279,4 @@ void __init setup_ioapic_dest(void)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dmi_system_id acpi_pciprobe_dmi_table[] = {
|
||||
static struct dmi_system_id acpi_pciprobe_dmi_table[] __devinitdata = {
|
||||
/*
|
||||
* Systems where PCI IO resource ISA alignment can be skipped
|
||||
* when the ISA enable bit in the bridge control is not set
|
||||
|
|
|
@ -50,7 +50,6 @@ config ACPI_SLEEP
|
|||
config ACPI_PROCFS
|
||||
bool "Deprecated /proc/acpi files"
|
||||
depends on PROC_FS
|
||||
default y
|
||||
---help---
|
||||
For backwards compatibility, this option allows
|
||||
deprecated /proc/acpi/ files to exist, even when
|
||||
|
@ -61,7 +60,6 @@ config ACPI_PROCFS
|
|||
/proc/acpi/info (/sys/modules/acpi/parameters/acpica_version)
|
||||
/proc/acpi/dsdt (/sys/firmware/acpi/tables/DSDT)
|
||||
/proc/acpi/fadt (/sys/firmware/acpi/tables/FACP)
|
||||
/proc/acpi/battery (/sys/class/power_supply)
|
||||
/proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer)
|
||||
/proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level)
|
||||
|
||||
|
@ -69,7 +67,21 @@ config ACPI_PROCFS
|
|||
and functions which do not yet exist in /sys.
|
||||
|
||||
Say N to delete /proc/acpi/ files that have moved to /sys/
|
||||
config ACPI_PROCFS_POWER
|
||||
bool "Deprecated power /proc/acpi folders"
|
||||
depends on PROC_FS
|
||||
default y
|
||||
---help---
|
||||
For backwards compatibility, this option allows
|
||||
deprecated power /proc/acpi/ folders to exist, even when
|
||||
they have been replaced by functions in /sys.
|
||||
The deprecated folders (and their replacements) include:
|
||||
/proc/acpi/battery/* (/sys/class/power_supply/*)
|
||||
/proc/acpi/ac_adapter/* (sys/class/power_supply/*)
|
||||
This option has no effect on /proc/acpi/ folders
|
||||
and functions, which do not yet exist in /sys
|
||||
|
||||
Say N to delete power /proc/acpi/ folders that have moved to /sys/
|
||||
config ACPI_PROC_EVENT
|
||||
bool "Deprecated /proc/acpi/event support"
|
||||
depends on PROC_FS
|
||||
|
|
|
@ -58,6 +58,6 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o
|
|||
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
|
||||
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
|
||||
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
|
||||
obj-y += cm_sbs.o
|
||||
obj-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
|
||||
obj-$(CONFIG_ACPI_SBS) += sbs.o
|
||||
obj-$(CONFIG_ACPI_SBS) += sbshc.o
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#endif
|
||||
|
@ -51,7 +51,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
|
|||
MODULE_DESCRIPTION("ACPI AC Adapter Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
extern struct proc_dir_entry *acpi_lock_ac_dir(void);
|
||||
extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
|
||||
static int acpi_ac_open_fs(struct inode *inode, struct file *file);
|
||||
|
@ -86,7 +86,7 @@ struct acpi_ac {
|
|||
|
||||
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger);
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
static const struct file_operations acpi_ac_fops = {
|
||||
.open = acpi_ac_open_fs,
|
||||
.read = seq_read,
|
||||
|
@ -136,7 +136,7 @@ static int acpi_ac_get_state(struct acpi_ac *ac)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -275,7 +275,7 @@ static int acpi_ac_add(struct acpi_device *device)
|
|||
if (result)
|
||||
goto end;
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
result = acpi_ac_add_fs(device);
|
||||
#endif
|
||||
if (result)
|
||||
|
@ -300,7 +300,7 @@ static int acpi_ac_add(struct acpi_device *device)
|
|||
|
||||
end:
|
||||
if (result) {
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_ac_remove_fs(device);
|
||||
#endif
|
||||
kfree(ac);
|
||||
|
@ -339,7 +339,7 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
|
|||
ACPI_ALL_NOTIFY, acpi_ac_notify);
|
||||
if (ac->charger.dev)
|
||||
power_supply_unregister(&ac->charger);
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_ac_remove_fs(device);
|
||||
#endif
|
||||
|
||||
|
@ -355,7 +355,7 @@ static int __init acpi_ac_init(void)
|
|||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_ac_dir = acpi_lock_ac_dir();
|
||||
if (!acpi_ac_dir)
|
||||
return -ENODEV;
|
||||
|
@ -363,7 +363,7 @@ static int __init acpi_ac_init(void)
|
|||
|
||||
result = acpi_bus_register_driver(&acpi_ac_driver);
|
||||
if (result < 0) {
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_unlock_ac_dir(acpi_ac_dir);
|
||||
#endif
|
||||
return -ENODEV;
|
||||
|
@ -377,7 +377,7 @@ static void __exit acpi_ac_exit(void)
|
|||
|
||||
acpi_bus_unregister_driver(&acpi_ac_driver);
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_unlock_ac_dir(acpi_ac_dir);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -63,7 +63,7 @@ static unsigned int cache_time = 1000;
|
|||
module_param(cache_time, uint, 0644);
|
||||
MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
|
||||
extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
|
||||
|
||||
|
@ -153,6 +153,8 @@ static int acpi_battery_get_property(struct power_supply *psy,
|
|||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else if (battery->state == 0)
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = acpi_battery_present(battery);
|
||||
|
@ -221,7 +223,7 @@ static enum power_supply_property energy_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
inline char *acpi_battery_units(struct acpi_battery *battery)
|
||||
{
|
||||
return (battery->power_unit)?"mA":"mW";
|
||||
|
@ -479,7 +481,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
|
|||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
static struct proc_dir_entry *acpi_battery_dir;
|
||||
|
||||
static int acpi_battery_print_info(struct seq_file *seq, int result)
|
||||
|
@ -786,7 +788,7 @@ static int acpi_battery_add(struct acpi_device *device)
|
|||
acpi_driver_data(device) = battery;
|
||||
mutex_init(&battery->lock);
|
||||
acpi_battery_update(battery);
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
result = acpi_battery_add_fs(device);
|
||||
if (result)
|
||||
goto end;
|
||||
|
@ -804,7 +806,7 @@ static int acpi_battery_add(struct acpi_device *device)
|
|||
device->status.battery_present ? "present" : "absent");
|
||||
end:
|
||||
if (result) {
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_battery_remove_fs(device);
|
||||
#endif
|
||||
kfree(battery);
|
||||
|
@ -823,7 +825,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
|
|||
status = acpi_remove_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY,
|
||||
acpi_battery_notify);
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_battery_remove_fs(device);
|
||||
#endif
|
||||
sysfs_remove_battery(battery);
|
||||
|
@ -859,13 +861,13 @@ static int __init acpi_battery_init(void)
|
|||
{
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_battery_dir = acpi_lock_battery_dir();
|
||||
if (!acpi_battery_dir)
|
||||
return -ENODEV;
|
||||
#endif
|
||||
if (acpi_bus_register_driver(&acpi_battery_driver) < 0) {
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_unlock_battery_dir(acpi_battery_dir);
|
||||
#endif
|
||||
return -ENODEV;
|
||||
|
@ -876,7 +878,7 @@ static int __init acpi_battery_init(void)
|
|||
static void __exit acpi_battery_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&acpi_battery_driver);
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_unlock_battery_dir(acpi_battery_dir);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
#undef PREFIX
|
||||
#define PREFIX "ACPI: EC: "
|
||||
|
||||
/* Uncomment next line to get verbose print outs*/
|
||||
/* #define DEBUG */
|
||||
|
||||
/* EC status register */
|
||||
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
|
||||
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
|
||||
|
@ -75,7 +78,10 @@ enum {
|
|||
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
|
||||
EC_FLAGS_QUERY_PENDING, /* Query is pending */
|
||||
EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
|
||||
EC_FLAGS_ONLY_IBF_GPE, /* Expect GPE only for IBF = 0 event */
|
||||
EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */
|
||||
EC_FLAGS_ADDRESS, /* Address is being written */
|
||||
EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
|
||||
EC_FLAGS_WDATA, /* Data is being written */
|
||||
};
|
||||
|
||||
static int acpi_ec_remove(struct acpi_device *device, int type);
|
||||
|
@ -131,21 +137,27 @@ static struct acpi_ec {
|
|||
|
||||
static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
|
||||
{
|
||||
return inb(ec->command_addr);
|
||||
u8 x = inb(ec->command_addr);
|
||||
pr_debug(PREFIX "---> status = 0x%2x\n", x);
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
|
||||
{
|
||||
u8 x = inb(ec->data_addr);
|
||||
pr_debug(PREFIX "---> data = 0x%2x\n", x);
|
||||
return inb(ec->data_addr);
|
||||
}
|
||||
|
||||
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
|
||||
{
|
||||
pr_debug(PREFIX "<--- command = 0x%2x\n", command);
|
||||
outb(command, ec->command_addr);
|
||||
}
|
||||
|
||||
static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
|
||||
{
|
||||
pr_debug(PREFIX "<--- data = 0x%2x\n", data);
|
||||
outb(data, ec->data_addr);
|
||||
}
|
||||
|
||||
|
@ -166,38 +178,54 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
|
|||
|
||||
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
|
||||
{
|
||||
int ret = 0;
|
||||
if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
|
||||
test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
|
||||
force_poll = 1;
|
||||
if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) &&
|
||||
test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags)))
|
||||
force_poll = 1;
|
||||
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
|
||||
likely(!force_poll)) {
|
||||
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
|
||||
msecs_to_jiffies(ACPI_EC_DELAY)))
|
||||
return 0;
|
||||
goto end;
|
||||
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
if (acpi_ec_check_status(ec, event)) {
|
||||
if (event == ACPI_EC_EVENT_OBF_1) {
|
||||
/* miss OBF = 1 GPE, don't expect it anymore */
|
||||
printk(KERN_INFO PREFIX "missing OBF_1 confirmation,"
|
||||
"switching to degraded mode.\n");
|
||||
set_bit(EC_FLAGS_ONLY_IBF_GPE, &ec->flags);
|
||||
if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
|
||||
/* miss address GPE, don't expect it anymore */
|
||||
pr_info(PREFIX "missing address confirmation, "
|
||||
"don't expect it any longer.\n");
|
||||
set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags);
|
||||
} else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) {
|
||||
/* miss write data GPE, don't expect it */
|
||||
pr_info(PREFIX "missing write data confirmation, "
|
||||
"don't expect it any longer.\n");
|
||||
set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags);
|
||||
} else {
|
||||
/* missing GPEs, switch back to poll mode */
|
||||
printk(KERN_INFO PREFIX "missing IBF_1 confirmations,"
|
||||
"switch off interrupt mode.\n");
|
||||
if (printk_ratelimit())
|
||||
pr_info(PREFIX "missing confirmations, "
|
||||
"switch off interrupt mode.\n");
|
||||
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
}
|
||||
return 0;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
|
||||
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
while (time_before(jiffies, delay)) {
|
||||
if (acpi_ec_check_status(ec, event))
|
||||
return 0;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
|
||||
pr_err(PREFIX "acpi_ec_wait timeout,"
|
||||
" status = %d, expect_event = %d\n",
|
||||
acpi_ec_read_status(ec), event);
|
||||
return -ETIME;
|
||||
ret = -ETIME;
|
||||
end:
|
||||
clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
|
||||
|
@ -208,22 +236,26 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
|
|||
int result = 0;
|
||||
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
acpi_ec_write_cmd(ec, command);
|
||||
|
||||
pr_debug(PREFIX "transaction start\n");
|
||||
for (; wdata_len > 0; --wdata_len) {
|
||||
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
|
||||
if (result) {
|
||||
printk(KERN_ERR PREFIX
|
||||
pr_err(PREFIX
|
||||
"write_cmd timeout, command = %d\n", command);
|
||||
goto end;
|
||||
}
|
||||
/* mark the address byte written to EC */
|
||||
if (rdata_len + wdata_len > 1)
|
||||
set_bit(EC_FLAGS_ADDRESS, &ec->flags);
|
||||
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
acpi_ec_write_data(ec, *(wdata++));
|
||||
}
|
||||
|
||||
if (!rdata_len) {
|
||||
set_bit(EC_FLAGS_WDATA, &ec->flags);
|
||||
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
|
||||
if (result) {
|
||||
printk(KERN_ERR PREFIX
|
||||
pr_err(PREFIX
|
||||
"finish-write timeout, command = %d\n", command);
|
||||
goto end;
|
||||
}
|
||||
|
@ -231,12 +263,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
|
|||
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
||||
|
||||
for (; rdata_len > 0; --rdata_len) {
|
||||
if (test_bit(EC_FLAGS_ONLY_IBF_GPE, &ec->flags))
|
||||
force_poll = 1;
|
||||
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll);
|
||||
if (result) {
|
||||
printk(KERN_ERR PREFIX "read timeout, command = %d\n",
|
||||
command);
|
||||
pr_err(PREFIX "read timeout, command = %d\n", command);
|
||||
goto end;
|
||||
}
|
||||
/* Don't expect GPE after last read */
|
||||
|
@ -245,6 +274,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
|
|||
*(rdata++) = acpi_ec_read_data(ec);
|
||||
}
|
||||
end:
|
||||
pr_debug(PREFIX "transaction end\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -273,8 +303,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
|
|||
|
||||
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
|
||||
if (status) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"input buffer is not empty, aborting transaction\n");
|
||||
pr_err(PREFIX "input buffer is not empty, "
|
||||
"aborting transaction\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -488,6 +518,7 @@ static u32 acpi_ec_gpe_handler(void *data)
|
|||
acpi_status status = AE_OK;
|
||||
struct acpi_ec *ec = data;
|
||||
|
||||
pr_debug(PREFIX "~~~> interrupt\n");
|
||||
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
|
||||
wake_up(&ec->wait);
|
||||
|
@ -498,8 +529,9 @@ static u32 acpi_ec_gpe_handler(void *data)
|
|||
acpi_ec_gpe_query, ec);
|
||||
} else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {
|
||||
/* this is non-query, must be confirmation */
|
||||
printk(KERN_INFO PREFIX "non-query interrupt received,"
|
||||
" switching to interrupt mode\n");
|
||||
if (printk_ratelimit())
|
||||
pr_info(PREFIX "non-query interrupt received,"
|
||||
" switching to interrupt mode\n");
|
||||
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
}
|
||||
|
||||
|
@ -701,10 +733,10 @@ static void ec_remove_handlers(struct acpi_ec *ec)
|
|||
{
|
||||
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
|
||||
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
|
||||
printk(KERN_ERR PREFIX "failed to remove space handler\n");
|
||||
pr_err(PREFIX "failed to remove space handler\n");
|
||||
if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
|
||||
&acpi_ec_gpe_handler)))
|
||||
printk(KERN_ERR PREFIX "failed to remove gpe handler\n");
|
||||
pr_err(PREFIX "failed to remove gpe handler\n");
|
||||
ec->handlers_installed = 0;
|
||||
}
|
||||
|
||||
|
@ -747,9 +779,9 @@ static int acpi_ec_add(struct acpi_device *device)
|
|||
first_ec = ec;
|
||||
acpi_driver_data(device) = ec;
|
||||
acpi_ec_add_fs(device);
|
||||
printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
|
||||
pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
|
||||
ec->gpe, ec->command_addr, ec->data_addr);
|
||||
printk(KERN_INFO PREFIX "driver started in %s mode\n",
|
||||
pr_info(PREFIX "driver started in %s mode\n",
|
||||
(test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll");
|
||||
return 0;
|
||||
}
|
||||
|
@ -875,18 +907,26 @@ int __init acpi_ec_ecdt_probe(void)
|
|||
status = acpi_get_table(ACPI_SIG_ECDT, 1,
|
||||
(struct acpi_table_header **)&ecdt_ptr);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
|
||||
pr_info(PREFIX "EC description table is found, configuring boot EC\n");
|
||||
boot_ec->command_addr = ecdt_ptr->control.address;
|
||||
boot_ec->data_addr = ecdt_ptr->data.address;
|
||||
boot_ec->gpe = ecdt_ptr->gpe;
|
||||
boot_ec->handle = ACPI_ROOT_OBJECT;
|
||||
} else {
|
||||
/* This workaround is needed only on some broken machines,
|
||||
* which require early EC, but fail to provide ECDT */
|
||||
acpi_handle x;
|
||||
printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
|
||||
status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
|
||||
boot_ec, NULL);
|
||||
/* Check that acpi_get_devices actually find something */
|
||||
if (ACPI_FAILURE(status) || !boot_ec->handle)
|
||||
goto error;
|
||||
/* We really need to limit this workaround, the only ASUS,
|
||||
* which needs it, has fake EC._INI method, so use it as flag.
|
||||
*/
|
||||
if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = ec_install_handlers(boot_ec);
|
||||
|
|
|
@ -387,17 +387,14 @@ acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
|
|||
if (!value)
|
||||
value = &dummy;
|
||||
|
||||
switch (width) {
|
||||
case 8:
|
||||
*value = 0;
|
||||
if (width <= 8) {
|
||||
*(u8 *) value = inb(port);
|
||||
break;
|
||||
case 16:
|
||||
} else if (width <= 16) {
|
||||
*(u16 *) value = inw(port);
|
||||
break;
|
||||
case 32:
|
||||
} else if (width <= 32) {
|
||||
*(u32 *) value = inl(port);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
@ -408,17 +405,13 @@ EXPORT_SYMBOL(acpi_os_read_port);
|
|||
|
||||
acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
|
||||
{
|
||||
switch (width) {
|
||||
case 8:
|
||||
if (width <= 8) {
|
||||
outb(value, port);
|
||||
break;
|
||||
case 16:
|
||||
} else if (width <= 16) {
|
||||
outw(value, port);
|
||||
break;
|
||||
case 32:
|
||||
} else if (width <= 32) {
|
||||
outl(value, port);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
|
|
@ -612,12 +612,6 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
|
|||
request_region(pr->throttling.address, 6, "ACPI CPU throttle");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
acpi_processor_ppc_has_changed(pr);
|
||||
#endif
|
||||
acpi_processor_get_throttling_info(pr);
|
||||
acpi_processor_get_limit_info(pr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -647,7 +641,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
|
|||
*/
|
||||
if (processor_device_array[pr->id] != NULL &&
|
||||
processor_device_array[pr->id] != device) {
|
||||
printk(KERN_WARNING "BIOS reported wrong ACPI id"
|
||||
printk(KERN_WARNING "BIOS reported wrong ACPI id "
|
||||
"for the processor\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -665,6 +659,12 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
|
|||
/* _PDC call should be done before doing anything else (if reqd.). */
|
||||
arch_acpi_processor_init_pdc(pr);
|
||||
acpi_processor_set_pdc(pr);
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
acpi_processor_ppc_has_changed(pr);
|
||||
#endif
|
||||
acpi_processor_get_throttling_info(pr);
|
||||
acpi_processor_get_limit_info(pr);
|
||||
|
||||
|
||||
acpi_processor_power_init(pr, device);
|
||||
|
||||
|
@ -684,7 +684,7 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
|
|||
{
|
||||
struct acpi_processor *pr = data;
|
||||
struct acpi_device *device = NULL;
|
||||
|
||||
int saved;
|
||||
|
||||
if (!pr)
|
||||
return;
|
||||
|
@ -694,7 +694,10 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
|
|||
|
||||
switch (event) {
|
||||
case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
|
||||
saved = pr->performance_platform_limit;
|
||||
acpi_processor_ppc_has_changed(pr);
|
||||
if (saved == pr->performance_platform_limit)
|
||||
break;
|
||||
acpi_bus_generate_proc_event(device, event,
|
||||
pr->performance_platform_limit);
|
||||
acpi_bus_generate_netlink_event(device->pnp.device_class,
|
||||
|
|
|
@ -197,6 +197,19 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
|
|||
return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
|
||||
}
|
||||
|
||||
static void acpi_safe_halt(void)
|
||||
{
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
/*
|
||||
* TS_POLLING-cleared state must be visible before we
|
||||
* test NEED_RESCHED:
|
||||
*/
|
||||
smp_mb();
|
||||
if (!need_resched())
|
||||
safe_halt();
|
||||
current_thread_info()->status |= TS_POLLING;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CPU_IDLE
|
||||
|
||||
static void
|
||||
|
@ -239,19 +252,6 @@ acpi_processor_power_activate(struct acpi_processor *pr,
|
|||
return;
|
||||
}
|
||||
|
||||
static void acpi_safe_halt(void)
|
||||
{
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
/*
|
||||
* TS_POLLING-cleared state must be visible before we
|
||||
* test NEED_RESCHED:
|
||||
*/
|
||||
smp_mb();
|
||||
if (!need_resched())
|
||||
safe_halt();
|
||||
current_thread_info()->status |= TS_POLLING;
|
||||
}
|
||||
|
||||
static atomic_t c3_cpu_count;
|
||||
|
||||
/* Common C-state entry for C2, C3, .. */
|
||||
|
@ -1373,15 +1373,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
|
|||
if (pr->flags.bm_check)
|
||||
acpi_idle_update_bm_rld(pr, cx);
|
||||
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
/*
|
||||
* TS_POLLING-cleared state must be visible before we test
|
||||
* NEED_RESCHED:
|
||||
*/
|
||||
smp_mb();
|
||||
if (!need_resched())
|
||||
safe_halt();
|
||||
current_thread_info()->status |= TS_POLLING;
|
||||
acpi_safe_halt();
|
||||
|
||||
cx->usage++;
|
||||
|
||||
|
@ -1399,6 +1391,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
|
|||
struct acpi_processor *pr;
|
||||
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
|
||||
u32 t1, t2;
|
||||
int sleep_ticks = 0;
|
||||
|
||||
pr = processors[smp_processor_id()];
|
||||
|
||||
if (unlikely(!pr))
|
||||
|
@ -1428,6 +1422,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
|
|||
ACPI_FLUSH_CPU_CACHE();
|
||||
|
||||
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
/* Tell the scheduler that we are going deep-idle: */
|
||||
sched_clock_idle_sleep_event();
|
||||
acpi_state_timer_broadcast(pr, cx, 1);
|
||||
acpi_idle_do_entry(cx);
|
||||
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
|
@ -1436,6 +1432,10 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
|
|||
/* TSC could halt in idle, so notify users */
|
||||
mark_tsc_unstable("TSC halts in idle");;
|
||||
#endif
|
||||
sleep_ticks = ticks_elapsed(t1, t2);
|
||||
|
||||
/* Tell the scheduler how much we idled: */
|
||||
sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
|
||||
|
||||
local_irq_enable();
|
||||
current_thread_info()->status |= TS_POLLING;
|
||||
|
@ -1443,7 +1443,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
|
|||
cx->usage++;
|
||||
|
||||
acpi_state_timer_broadcast(pr, cx, 0);
|
||||
cx->time += ticks_elapsed(t1, t2);
|
||||
cx->time += sleep_ticks;
|
||||
return ticks_elapsed_in_us(t1, t2);
|
||||
}
|
||||
|
||||
|
@ -1463,6 +1463,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
|||
struct acpi_processor *pr;
|
||||
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
|
||||
u32 t1, t2;
|
||||
int sleep_ticks = 0;
|
||||
|
||||
pr = processors[smp_processor_id()];
|
||||
|
||||
if (unlikely(!pr))
|
||||
|
@ -1471,6 +1473,15 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
|||
if (acpi_idle_suspend)
|
||||
return(acpi_idle_enter_c1(dev, state));
|
||||
|
||||
if (acpi_idle_bm_check()) {
|
||||
if (dev->safe_state) {
|
||||
return dev->safe_state->enter(dev, dev->safe_state);
|
||||
} else {
|
||||
acpi_safe_halt();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_disable();
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
/*
|
||||
|
@ -1485,38 +1496,45 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Tell the scheduler that we are going deep-idle: */
|
||||
sched_clock_idle_sleep_event();
|
||||
/*
|
||||
* Must be done before busmaster disable as we might need to
|
||||
* access HPET !
|
||||
*/
|
||||
acpi_state_timer_broadcast(pr, cx, 1);
|
||||
|
||||
if (acpi_idle_bm_check()) {
|
||||
cx = pr->power.bm_state;
|
||||
|
||||
acpi_idle_update_bm_rld(pr, cx);
|
||||
|
||||
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
acpi_idle_do_entry(cx);
|
||||
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
} else {
|
||||
acpi_idle_update_bm_rld(pr, cx);
|
||||
acpi_idle_update_bm_rld(pr, cx);
|
||||
|
||||
/*
|
||||
* disable bus master
|
||||
* bm_check implies we need ARB_DIS
|
||||
* !bm_check implies we need cache flush
|
||||
* bm_control implies whether we can do ARB_DIS
|
||||
*
|
||||
* That leaves a case where bm_check is set and bm_control is
|
||||
* not set. In that case we cannot do much, we enter C3
|
||||
* without doing anything.
|
||||
*/
|
||||
if (pr->flags.bm_check && pr->flags.bm_control) {
|
||||
spin_lock(&c3_lock);
|
||||
c3_cpu_count++;
|
||||
/* Disable bus master arbitration when all CPUs are in C3 */
|
||||
if (c3_cpu_count == num_online_cpus())
|
||||
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
|
||||
spin_unlock(&c3_lock);
|
||||
} else if (!pr->flags.bm_check) {
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
}
|
||||
|
||||
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
acpi_idle_do_entry(cx);
|
||||
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
acpi_idle_do_entry(cx);
|
||||
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
|
||||
/* Re-enable bus master arbitration */
|
||||
if (pr->flags.bm_check && pr->flags.bm_control) {
|
||||
spin_lock(&c3_lock);
|
||||
/* Re-enable bus master arbitration */
|
||||
if (c3_cpu_count == num_online_cpus())
|
||||
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
|
||||
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
|
||||
c3_cpu_count--;
|
||||
spin_unlock(&c3_lock);
|
||||
}
|
||||
|
@ -1525,6 +1543,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
|||
/* TSC could halt in idle, so notify users */
|
||||
mark_tsc_unstable("TSC halts in idle");
|
||||
#endif
|
||||
sleep_ticks = ticks_elapsed(t1, t2);
|
||||
/* Tell the scheduler how much we idled: */
|
||||
sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
|
||||
|
||||
local_irq_enable();
|
||||
current_thread_info()->status |= TS_POLLING;
|
||||
|
@ -1532,7 +1553,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
|||
cx->usage++;
|
||||
|
||||
acpi_state_timer_broadcast(pr, cx, 0);
|
||||
cx->time += ticks_elapsed(t1, t2);
|
||||
cx->time += sleep_ticks;
|
||||
return ticks_elapsed_in_us(t1, t2);
|
||||
}
|
||||
|
||||
|
@ -1584,12 +1605,14 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
|
|||
case ACPI_STATE_C1:
|
||||
state->flags |= CPUIDLE_FLAG_SHALLOW;
|
||||
state->enter = acpi_idle_enter_c1;
|
||||
dev->safe_state = state;
|
||||
break;
|
||||
|
||||
case ACPI_STATE_C2:
|
||||
state->flags |= CPUIDLE_FLAG_BALANCED;
|
||||
state->flags |= CPUIDLE_FLAG_TIME_VALID;
|
||||
state->enter = acpi_idle_enter_simple;
|
||||
dev->safe_state = state;
|
||||
break;
|
||||
|
||||
case ACPI_STATE_C3:
|
||||
|
@ -1610,14 +1633,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
|
|||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
/* find the deepest state that can handle active BM */
|
||||
if (pr->flags.bm_check) {
|
||||
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++)
|
||||
if (pr->power.states[i].type == ACPI_STATE_C3)
|
||||
break;
|
||||
pr->power.bm_state = &pr->power.states[i-1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,55 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
|
|||
|
||||
int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
|
||||
{
|
||||
return acpi_processor_get_platform_limit(pr);
|
||||
int result = 0;
|
||||
int throttling_limit;
|
||||
int current_state;
|
||||
struct acpi_processor_limit *limit;
|
||||
int target_state;
|
||||
|
||||
result = acpi_processor_get_platform_limit(pr);
|
||||
if (result) {
|
||||
/* Throttling Limit is unsupported */
|
||||
return result;
|
||||
}
|
||||
|
||||
throttling_limit = pr->throttling_platform_limit;
|
||||
if (throttling_limit >= pr->throttling.state_count) {
|
||||
/* Uncorrect Throttling Limit */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
current_state = pr->throttling.state;
|
||||
if (current_state > throttling_limit) {
|
||||
/*
|
||||
* The current state can meet the requirement of
|
||||
* _TPC limit. But it is reasonable that OSPM changes
|
||||
* t-states from high to low for better performance.
|
||||
* Of course the limit condition of thermal
|
||||
* and user should be considered.
|
||||
*/
|
||||
limit = &pr->limit;
|
||||
target_state = throttling_limit;
|
||||
if (limit->thermal.tx > target_state)
|
||||
target_state = limit->thermal.tx;
|
||||
if (limit->user.tx > target_state)
|
||||
target_state = limit->user.tx;
|
||||
} else if (current_state == throttling_limit) {
|
||||
/*
|
||||
* Unnecessary to change the throttling state
|
||||
*/
|
||||
return 0;
|
||||
} else {
|
||||
/*
|
||||
* If the current state is lower than the limit of _TPC, it
|
||||
* will be forced to switch to the throttling state defined
|
||||
* by throttling_platfor_limit.
|
||||
* Because the previous state meets with the limit condition
|
||||
* of thermal and user, it is unnecessary to check it again.
|
||||
*/
|
||||
target_state = throttling_limit;
|
||||
}
|
||||
return acpi_processor_set_throttling(pr, target_state);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -83,6 +131,7 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
|
|||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *ptc = NULL;
|
||||
union acpi_object obj = { 0 };
|
||||
struct acpi_processor_throttling *throttling;
|
||||
|
||||
status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
@ -134,6 +183,22 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
|
|||
memcpy(&pr->throttling.status_register, obj.buffer.pointer,
|
||||
sizeof(struct acpi_ptc_register));
|
||||
|
||||
throttling = &pr->throttling;
|
||||
|
||||
if ((throttling->control_register.bit_width +
|
||||
throttling->control_register.bit_offset) > 32) {
|
||||
printk(KERN_ERR PREFIX "Invalid _PTC control register\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((throttling->status_register.bit_width +
|
||||
throttling->status_register.bit_offset) > 32) {
|
||||
printk(KERN_ERR PREFIX "Invalid _PTC status register\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
|
||||
|
@ -328,44 +393,132 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_read_throttling_status(struct acpi_processor_throttling
|
||||
*throttling)
|
||||
#ifdef CONFIG_X86
|
||||
static int acpi_throttling_rdmsr(struct acpi_processor *pr,
|
||||
acpi_integer * value)
|
||||
{
|
||||
int value = -1;
|
||||
struct cpuinfo_x86 *c;
|
||||
u64 msr_high, msr_low;
|
||||
unsigned int cpu;
|
||||
u64 msr = 0;
|
||||
int ret = -1;
|
||||
|
||||
cpu = pr->id;
|
||||
c = &cpu_data(cpu);
|
||||
|
||||
if ((c->x86_vendor != X86_VENDOR_INTEL) ||
|
||||
!cpu_has(c, X86_FEATURE_ACPI)) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"HARDWARE addr space,NOT supported yet\n");
|
||||
} else {
|
||||
msr_low = 0;
|
||||
msr_high = 0;
|
||||
rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL,
|
||||
(u32 *)&msr_low , (u32 *) &msr_high);
|
||||
msr = (msr_high << 32) | msr_low;
|
||||
*value = (acpi_integer) msr;
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
|
||||
{
|
||||
struct cpuinfo_x86 *c;
|
||||
unsigned int cpu;
|
||||
int ret = -1;
|
||||
u64 msr;
|
||||
|
||||
cpu = pr->id;
|
||||
c = &cpu_data(cpu);
|
||||
|
||||
if ((c->x86_vendor != X86_VENDOR_INTEL) ||
|
||||
!cpu_has(c, X86_FEATURE_ACPI)) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"HARDWARE addr space,NOT supported yet\n");
|
||||
} else {
|
||||
msr = value;
|
||||
wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL,
|
||||
msr & 0xffffffff, msr >> 32);
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int acpi_throttling_rdmsr(struct acpi_processor *pr,
|
||||
acpi_integer * value)
|
||||
{
|
||||
printk(KERN_ERR PREFIX
|
||||
"HARDWARE addr space,NOT supported yet\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
|
||||
{
|
||||
printk(KERN_ERR PREFIX
|
||||
"HARDWARE addr space,NOT supported yet\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int acpi_read_throttling_status(struct acpi_processor *pr,
|
||||
acpi_integer *value)
|
||||
{
|
||||
u32 bit_width, bit_offset;
|
||||
u64 ptc_value;
|
||||
u64 ptc_mask;
|
||||
struct acpi_processor_throttling *throttling;
|
||||
int ret = -1;
|
||||
|
||||
throttling = &pr->throttling;
|
||||
switch (throttling->status_register.space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
ptc_value = 0;
|
||||
bit_width = throttling->status_register.bit_width;
|
||||
bit_offset = throttling->status_register.bit_offset;
|
||||
|
||||
acpi_os_read_port((acpi_io_address) throttling->status_register.
|
||||
address, &value,
|
||||
(u32) throttling->status_register.bit_width *
|
||||
8);
|
||||
address, (u32 *) &ptc_value,
|
||||
(u32) (bit_width + bit_offset));
|
||||
ptc_mask = (1 << bit_width) - 1;
|
||||
*value = (acpi_integer) ((ptc_value >> bit_offset) & ptc_mask);
|
||||
ret = 0;
|
||||
break;
|
||||
case ACPI_ADR_SPACE_FIXED_HARDWARE:
|
||||
printk(KERN_ERR PREFIX
|
||||
"HARDWARE addr space,NOT supported yet\n");
|
||||
ret = acpi_throttling_rdmsr(pr, value);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PREFIX "Unknown addr space %d\n",
|
||||
(u32) (throttling->status_register.space_id));
|
||||
}
|
||||
return value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_write_throttling_state(struct acpi_processor_throttling
|
||||
*throttling, int value)
|
||||
static int acpi_write_throttling_state(struct acpi_processor *pr,
|
||||
acpi_integer value)
|
||||
{
|
||||
u32 bit_width, bit_offset;
|
||||
u64 ptc_value;
|
||||
u64 ptc_mask;
|
||||
struct acpi_processor_throttling *throttling;
|
||||
int ret = -1;
|
||||
|
||||
throttling = &pr->throttling;
|
||||
switch (throttling->control_register.space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
bit_width = throttling->control_register.bit_width;
|
||||
bit_offset = throttling->control_register.bit_offset;
|
||||
ptc_mask = (1 << bit_width) - 1;
|
||||
ptc_value = value & ptc_mask;
|
||||
|
||||
acpi_os_write_port((acpi_io_address) throttling->
|
||||
control_register.address, value,
|
||||
(u32) throttling->control_register.
|
||||
bit_width * 8);
|
||||
control_register.address,
|
||||
(u32) (ptc_value << bit_offset),
|
||||
(u32) (bit_width + bit_offset));
|
||||
ret = 0;
|
||||
break;
|
||||
case ACPI_ADR_SPACE_FIXED_HARDWARE:
|
||||
printk(KERN_ERR PREFIX
|
||||
"HARDWARE addr space,NOT supported yet\n");
|
||||
ret = acpi_throttling_wrmsr(pr, value);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PREFIX "Unknown addr space %d\n",
|
||||
|
@ -374,7 +527,8 @@ static int acpi_write_throttling_state(struct acpi_processor_throttling
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
|
||||
static int acpi_get_throttling_state(struct acpi_processor *pr,
|
||||
acpi_integer value)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -390,22 +544,26 @@ static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
|
|||
return i;
|
||||
}
|
||||
|
||||
static int acpi_get_throttling_value(struct acpi_processor *pr, int state)
|
||||
static int acpi_get_throttling_value(struct acpi_processor *pr,
|
||||
int state, acpi_integer *value)
|
||||
{
|
||||
int value = -1;
|
||||
int ret = -1;
|
||||
|
||||
if (state >= 0 && state <= pr->throttling.state_count) {
|
||||
struct acpi_processor_tx_tss *tx =
|
||||
(struct acpi_processor_tx_tss *)&(pr->throttling.
|
||||
states_tss[state]);
|
||||
value = tx->control;
|
||||
*value = tx->control;
|
||||
ret = 0;
|
||||
}
|
||||
return value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
|
||||
{
|
||||
int state = 0;
|
||||
u32 value = 0;
|
||||
int ret;
|
||||
acpi_integer value;
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
@ -415,8 +573,9 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
|
|||
|
||||
pr->throttling.state = 0;
|
||||
local_irq_disable();
|
||||
value = acpi_read_throttling_status(&pr->throttling);
|
||||
if (value >= 0) {
|
||||
value = 0;
|
||||
ret = acpi_read_throttling_status(pr, &value);
|
||||
if (ret >= 0) {
|
||||
state = acpi_get_throttling_state(pr, value);
|
||||
pr->throttling.state = state;
|
||||
}
|
||||
|
@ -430,6 +589,40 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
|
|||
return pr->throttling.acpi_processor_get_throttling(pr);
|
||||
}
|
||||
|
||||
static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
|
||||
{
|
||||
int i, step;
|
||||
|
||||
if (!pr->throttling.address) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
|
||||
return -EINVAL;
|
||||
} else if (!pr->throttling.duty_width) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* TBD: Support duty_cycle values that span bit 4. */
|
||||
else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
|
||||
printk(KERN_WARNING PREFIX "duty_cycle spans bit 4\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
|
||||
|
||||
/*
|
||||
* Compute state values. Note that throttling displays a linear power
|
||||
* performance relationship (at 50% performance the CPU will consume
|
||||
* 50% power). Values are in 1/10th of a percent to preserve accuracy.
|
||||
*/
|
||||
|
||||
step = (1000 / pr->throttling.state_count);
|
||||
|
||||
for (i = 0; i < pr->throttling.state_count; i++) {
|
||||
pr->throttling.states[i].performance = 1000 - step * i;
|
||||
pr->throttling.states[i].power = 1000 - step * i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
|
||||
int state)
|
||||
{
|
||||
|
@ -506,7 +699,8 @@ static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
|
|||
static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
|
||||
int state)
|
||||
{
|
||||
u32 value = 0;
|
||||
int ret;
|
||||
acpi_integer value;
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
@ -524,10 +718,10 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
|
|||
return -EPERM;
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
value = acpi_get_throttling_value(pr, state);
|
||||
if (value >= 0) {
|
||||
acpi_write_throttling_state(&pr->throttling, value);
|
||||
value = 0;
|
||||
ret = acpi_get_throttling_value(pr, state, &value);
|
||||
if (ret >= 0) {
|
||||
acpi_write_throttling_state(pr, value);
|
||||
pr->throttling.state = state;
|
||||
}
|
||||
local_irq_enable();
|
||||
|
@ -543,8 +737,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
|
|||
int acpi_processor_get_throttling_info(struct acpi_processor *pr)
|
||||
{
|
||||
int result = 0;
|
||||
int step = 0;
|
||||
int i = 0;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
|
||||
|
@ -563,6 +755,8 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
|
|||
acpi_processor_get_throttling_states(pr) ||
|
||||
acpi_processor_get_platform_limit(pr))
|
||||
{
|
||||
if (acpi_processor_get_fadt_info(pr))
|
||||
return 0;
|
||||
pr->throttling.acpi_processor_get_throttling =
|
||||
&acpi_processor_get_throttling_fadt;
|
||||
pr->throttling.acpi_processor_set_throttling =
|
||||
|
@ -576,19 +770,6 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
|
|||
|
||||
acpi_processor_get_tsd(pr);
|
||||
|
||||
if (!pr->throttling.address) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
|
||||
return 0;
|
||||
} else if (!pr->throttling.duty_width) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n"));
|
||||
return 0;
|
||||
}
|
||||
/* TBD: Support duty_cycle values that span bit 4. */
|
||||
else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
|
||||
printk(KERN_WARNING PREFIX "duty_cycle spans bit 4\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* PIIX4 Errata: We don't support throttling on the original PIIX4.
|
||||
* This shouldn't be an issue as few (if any) mobile systems ever
|
||||
|
@ -600,21 +781,6 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
|
||||
|
||||
/*
|
||||
* Compute state values. Note that throttling displays a linear power/
|
||||
* performance relationship (at 50% performance the CPU will consume
|
||||
* 50% power). Values are in 1/10th of a percent to preserve accuracy.
|
||||
*/
|
||||
|
||||
step = (1000 / pr->throttling.state_count);
|
||||
|
||||
for (i = 0; i < pr->throttling.state_count; i++) {
|
||||
pr->throttling.states[i].performance = step * i;
|
||||
pr->throttling.states[i].power = step * i;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
|
||||
pr->throttling.state_count));
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -88,7 +88,7 @@ MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
|
|||
struct acpi_battery {
|
||||
struct power_supply bat;
|
||||
struct acpi_sbs *sbs;
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
struct proc_dir_entry *proc_entry;
|
||||
#endif
|
||||
unsigned long update_time;
|
||||
|
@ -113,6 +113,7 @@ struct acpi_battery {
|
|||
u16 spec;
|
||||
u8 id;
|
||||
u8 present:1;
|
||||
u8 have_sysfs_alarm:1;
|
||||
};
|
||||
|
||||
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
|
||||
|
@ -122,7 +123,7 @@ struct acpi_sbs {
|
|||
struct acpi_device *device;
|
||||
struct acpi_smb_hc *hc;
|
||||
struct mutex lock;
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
struct proc_dir_entry *charger_entry;
|
||||
#endif
|
||||
struct acpi_battery battery[MAX_SBS_BAT];
|
||||
|
@ -468,7 +469,7 @@ static struct device_attribute alarm_attr = {
|
|||
FS Interface (/proc/acpi)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
/* Generic Routines */
|
||||
static int
|
||||
acpi_sbs_add_fs(struct proc_dir_entry **dir,
|
||||
|
@ -789,7 +790,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
|
|||
return result;
|
||||
|
||||
sprintf(battery->name, ACPI_BATTERY_DIR_NAME, id);
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_sbs_add_fs(&battery->proc_entry, acpi_battery_dir,
|
||||
battery->name, &acpi_battery_info_fops,
|
||||
&acpi_battery_state_fops, &acpi_battery_alarm_fops,
|
||||
|
@ -808,7 +809,13 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
|
|||
}
|
||||
battery->bat.get_property = acpi_sbs_battery_get_property;
|
||||
result = power_supply_register(&sbs->device->dev, &battery->bat);
|
||||
device_create_file(battery->bat.dev, &alarm_attr);
|
||||
if (result)
|
||||
goto end;
|
||||
result = device_create_file(battery->bat.dev, &alarm_attr);
|
||||
if (result)
|
||||
goto end;
|
||||
battery->have_sysfs_alarm = 1;
|
||||
end:
|
||||
printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
|
||||
ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
|
||||
battery->name, sbs->battery->present ? "present" : "absent");
|
||||
|
@ -817,14 +824,16 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
|
|||
|
||||
static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
|
||||
{
|
||||
if (sbs->battery[id].bat.dev)
|
||||
device_remove_file(sbs->battery[id].bat.dev, &alarm_attr);
|
||||
power_supply_unregister(&sbs->battery[id].bat);
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
if (sbs->battery[id].proc_entry) {
|
||||
acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry),
|
||||
acpi_battery_dir);
|
||||
struct acpi_battery *battery = &sbs->battery[id];
|
||||
|
||||
if (battery->bat.dev) {
|
||||
if (battery->have_sysfs_alarm)
|
||||
device_remove_file(battery->bat.dev, &alarm_attr);
|
||||
power_supply_unregister(&battery->bat);
|
||||
}
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
if (battery->proc_entry)
|
||||
acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -835,7 +844,7 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
|
|||
result = acpi_ac_get_present(sbs);
|
||||
if (result)
|
||||
goto end;
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
result = acpi_sbs_add_fs(&sbs->charger_entry, acpi_ac_dir,
|
||||
ACPI_AC_DIR_NAME, NULL,
|
||||
&acpi_ac_state_fops, NULL, sbs);
|
||||
|
@ -859,7 +868,7 @@ static void acpi_charger_remove(struct acpi_sbs *sbs)
|
|||
{
|
||||
if (sbs->charger.dev)
|
||||
power_supply_unregister(&sbs->charger);
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
if (sbs->charger_entry)
|
||||
acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
|
||||
#endif
|
||||
|
@ -965,7 +974,7 @@ static int acpi_sbs_remove(struct acpi_device *device, int type)
|
|||
|
||||
static void acpi_sbs_rmdirs(void)
|
||||
{
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
if (acpi_ac_dir) {
|
||||
acpi_unlock_ac_dir(acpi_ac_dir);
|
||||
acpi_ac_dir = NULL;
|
||||
|
@ -1004,7 +1013,7 @@ static int __init acpi_sbs_init(void)
|
|||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
acpi_ac_dir = acpi_lock_ac_dir();
|
||||
if (!acpi_ac_dir)
|
||||
return -ENODEV;
|
||||
|
|
|
@ -449,7 +449,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
|
|||
/* XSDT has NULL entry, RSDT is used */
|
||||
address = rsdt_address;
|
||||
table_entry_size = sizeof(u32);
|
||||
ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry,"
|
||||
ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry, "
|
||||
"using RSDT"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/input.h>
|
||||
|
@ -135,8 +136,8 @@ struct acpi_video_bus {
|
|||
u8 attached_count;
|
||||
struct acpi_video_bus_cap cap;
|
||||
struct acpi_video_bus_flags flags;
|
||||
struct semaphore sem;
|
||||
struct list_head video_device_list;
|
||||
struct mutex device_list_lock; /* protects video_device_list */
|
||||
struct proc_dir_entry *dir;
|
||||
struct input_dev *input;
|
||||
char phys[32]; /* for input device */
|
||||
|
@ -896,7 +897,7 @@ acpi_video_device_write_brightness(struct file *file,
|
|||
{
|
||||
struct seq_file *m = file->private_data;
|
||||
struct acpi_video_device *dev = m->private;
|
||||
char str[4] = { 0 };
|
||||
char str[5] = { 0 };
|
||||
unsigned int level = 0;
|
||||
int i;
|
||||
|
||||
|
@ -1436,9 +1437,9 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
down(&video->sem);
|
||||
mutex_lock(&video->device_list_lock);
|
||||
list_add_tail(&data->entry, &video->video_device_list);
|
||||
up(&video->sem);
|
||||
mutex_unlock(&video->device_list_lock);
|
||||
|
||||
acpi_video_device_add_fs(device);
|
||||
|
||||
|
@ -1462,12 +1463,14 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
|
|||
|
||||
static void acpi_video_device_rebind(struct acpi_video_bus *video)
|
||||
{
|
||||
struct list_head *node, *next;
|
||||
list_for_each_safe(node, next, &video->video_device_list) {
|
||||
struct acpi_video_device *dev =
|
||||
container_of(node, struct acpi_video_device, entry);
|
||||
struct acpi_video_device *dev;
|
||||
|
||||
mutex_lock(&video->device_list_lock);
|
||||
|
||||
list_for_each_entry(dev, &video->video_device_list, entry)
|
||||
acpi_video_device_bind(video, dev);
|
||||
}
|
||||
|
||||
mutex_unlock(&video->device_list_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1592,30 +1595,33 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
|
|||
|
||||
static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
|
||||
{
|
||||
struct list_head *node, *next;
|
||||
struct list_head *node;
|
||||
struct acpi_video_device *dev = NULL;
|
||||
struct acpi_video_device *dev_next = NULL;
|
||||
struct acpi_video_device *dev_prev = NULL;
|
||||
unsigned long state;
|
||||
int status = 0;
|
||||
|
||||
mutex_lock(&video->device_list_lock);
|
||||
|
||||
list_for_each_safe(node, next, &video->video_device_list) {
|
||||
list_for_each(node, &video->video_device_list) {
|
||||
dev = container_of(node, struct acpi_video_device, entry);
|
||||
status = acpi_video_device_get_state(dev, &state);
|
||||
if (state & 0x2) {
|
||||
dev_next =
|
||||
container_of(node->next, struct acpi_video_device,
|
||||
entry);
|
||||
dev_prev =
|
||||
container_of(node->prev, struct acpi_video_device,
|
||||
entry);
|
||||
dev_next = container_of(node->next,
|
||||
struct acpi_video_device, entry);
|
||||
dev_prev = container_of(node->prev,
|
||||
struct acpi_video_device, entry);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
dev_next = container_of(node->next, struct acpi_video_device, entry);
|
||||
dev_prev = container_of(node->prev, struct acpi_video_device, entry);
|
||||
out:
|
||||
|
||||
out:
|
||||
mutex_unlock(&video->device_list_lock);
|
||||
|
||||
switch (event) {
|
||||
case ACPI_VIDEO_NOTIFY_CYCLE:
|
||||
case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
|
||||
|
@ -1691,24 +1697,17 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
|
|||
struct acpi_device *device)
|
||||
{
|
||||
int status = 0;
|
||||
struct list_head *node, *next;
|
||||
|
||||
struct acpi_device *dev;
|
||||
|
||||
acpi_video_device_enumerate(video);
|
||||
|
||||
list_for_each_safe(node, next, &device->children) {
|
||||
struct acpi_device *dev =
|
||||
list_entry(node, struct acpi_device, node);
|
||||
|
||||
if (!dev)
|
||||
continue;
|
||||
list_for_each_entry(dev, &device->children, node) {
|
||||
|
||||
status = acpi_video_bus_get_one_device(dev, video);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
@ -1724,9 +1723,6 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
|
|||
|
||||
video = device->video;
|
||||
|
||||
down(&video->sem);
|
||||
list_del(&device->entry);
|
||||
up(&video->sem);
|
||||
acpi_video_device_remove_fs(device->dev);
|
||||
|
||||
status = acpi_remove_notify_handler(device->dev->handle,
|
||||
|
@ -1734,32 +1730,34 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
|
|||
acpi_video_device_notify);
|
||||
backlight_device_unregister(device->backlight);
|
||||
video_output_unregister(device->output_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
|
||||
{
|
||||
int status;
|
||||
struct list_head *node, *next;
|
||||
struct acpi_video_device *dev, *next;
|
||||
|
||||
mutex_lock(&video->device_list_lock);
|
||||
|
||||
list_for_each_safe(node, next, &video->video_device_list) {
|
||||
struct acpi_video_device *data =
|
||||
list_entry(node, struct acpi_video_device, entry);
|
||||
if (!data)
|
||||
continue;
|
||||
list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
|
||||
|
||||
status = acpi_video_bus_put_one_device(data);
|
||||
status = acpi_video_bus_put_one_device(dev);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(KERN_WARNING PREFIX
|
||||
"hhuuhhuu bug in acpi video driver.\n");
|
||||
|
||||
if (data->brightness)
|
||||
kfree(data->brightness->levels);
|
||||
kfree(data->brightness);
|
||||
kfree(data);
|
||||
if (dev->brightness) {
|
||||
kfree(dev->brightness->levels);
|
||||
kfree(dev->brightness);
|
||||
}
|
||||
list_del(&dev->entry);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
mutex_unlock(&video->device_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1782,9 +1780,6 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
|
|||
struct input_dev *input;
|
||||
int keycode;
|
||||
|
||||
|
||||
printk("video bus notify\n");
|
||||
|
||||
if (!video)
|
||||
return;
|
||||
|
||||
|
@ -1897,14 +1892,10 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
|
|||
static int instance;
|
||||
static int acpi_video_bus_add(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = 0;
|
||||
struct acpi_video_bus *video = NULL;
|
||||
acpi_status status;
|
||||
struct acpi_video_bus *video;
|
||||
struct input_dev *input;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
int error;
|
||||
|
||||
video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
|
||||
if (!video)
|
||||
|
@ -1923,15 +1914,15 @@ static int acpi_video_bus_add(struct acpi_device *device)
|
|||
acpi_driver_data(device) = video;
|
||||
|
||||
acpi_video_bus_find_cap(video);
|
||||
result = acpi_video_bus_check(video);
|
||||
if (result)
|
||||
goto end;
|
||||
error = acpi_video_bus_check(video);
|
||||
if (error)
|
||||
goto err_free_video;
|
||||
|
||||
result = acpi_video_bus_add_fs(device);
|
||||
if (result)
|
||||
goto end;
|
||||
error = acpi_video_bus_add_fs(device);
|
||||
if (error)
|
||||
goto err_free_video;
|
||||
|
||||
init_MUTEX(&video->sem);
|
||||
mutex_init(&video->device_list_lock);
|
||||
INIT_LIST_HEAD(&video->video_device_list);
|
||||
|
||||
acpi_video_bus_get_devices(video, device);
|
||||
|
@ -1943,16 +1934,15 @@ static int acpi_video_bus_add(struct acpi_device *device)
|
|||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error installing notify handler\n"));
|
||||
acpi_video_bus_stop_devices(video);
|
||||
acpi_video_bus_put_devices(video);
|
||||
kfree(video->attached_array);
|
||||
acpi_video_bus_remove_fs(device);
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
error = -ENODEV;
|
||||
goto err_stop_video;
|
||||
}
|
||||
|
||||
|
||||
video->input = input = input_allocate_device();
|
||||
if (!input) {
|
||||
error = -ENOMEM;
|
||||
goto err_uninstall_notify;
|
||||
}
|
||||
|
||||
snprintf(video->phys, sizeof(video->phys),
|
||||
"%s/video/input0", acpi_device_hid(video->device));
|
||||
|
@ -1961,6 +1951,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
|
|||
input->phys = video->phys;
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.product = 0x06;
|
||||
input->dev.parent = &device->dev;
|
||||
input->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
|
||||
set_bit(KEY_VIDEO_NEXT, input->keybit);
|
||||
|
@ -1971,18 +1962,10 @@ static int acpi_video_bus_add(struct acpi_device *device)
|
|||
set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
|
||||
set_bit(KEY_DISPLAY_OFF, input->keybit);
|
||||
set_bit(KEY_UNKNOWN, input->keybit);
|
||||
result = input_register_device(input);
|
||||
if (result) {
|
||||
acpi_remove_notify_handler(video->device->handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acpi_video_bus_notify);
|
||||
acpi_video_bus_stop_devices(video);
|
||||
acpi_video_bus_put_devices(video);
|
||||
kfree(video->attached_array);
|
||||
acpi_video_bus_remove_fs(device);
|
||||
goto end;
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error)
|
||||
goto err_free_input_dev;
|
||||
|
||||
printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n",
|
||||
ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
|
||||
|
@ -1990,11 +1973,23 @@ static int acpi_video_bus_add(struct acpi_device *device)
|
|||
video->flags.rom ? "yes" : "no",
|
||||
video->flags.post ? "yes" : "no");
|
||||
|
||||
end:
|
||||
if (result)
|
||||
kfree(video);
|
||||
return 0;
|
||||
|
||||
return result;
|
||||
err_free_input_dev:
|
||||
input_free_device(input);
|
||||
err_uninstall_notify:
|
||||
acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_video_bus_notify);
|
||||
err_stop_video:
|
||||
acpi_video_bus_stop_devices(video);
|
||||
acpi_video_bus_put_devices(video);
|
||||
kfree(video->attached_array);
|
||||
acpi_video_bus_remove_fs(device);
|
||||
err_free_video:
|
||||
kfree(video);
|
||||
acpi_driver_data(device) = NULL;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int acpi_video_bus_remove(struct acpi_device *device, int type)
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define IBM_VERSION "0.16"
|
||||
#define IBM_VERSION "0.17"
|
||||
#define TPACPI_SYSFS_VERSION 0x020000
|
||||
|
||||
/*
|
||||
|
@ -964,15 +964,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
|
||||
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
|
||||
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
|
||||
KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
|
||||
KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
|
||||
/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
|
||||
KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
|
||||
KEY_RESERVED, /* 0x10: FN+END (brightness down) */
|
||||
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
|
||||
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
|
||||
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
|
||||
KEY_VOLUMEUP, /* 0x14: VOLUME UP */
|
||||
KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
|
||||
KEY_MUTE, /* 0x16: MUTE */
|
||||
KEY_RESERVED, /* 0x14: VOLUME UP */
|
||||
KEY_RESERVED, /* 0x15: VOLUME DOWN */
|
||||
KEY_RESERVED, /* 0x16: MUTE */
|
||||
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
|
||||
/* (assignments unknown, please report if found) */
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
|
@ -993,9 +993,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
|
||||
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
|
||||
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
|
||||
KEY_VOLUMEUP, /* 0x14: VOLUME UP */
|
||||
KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
|
||||
KEY_MUTE, /* 0x16: MUTE */
|
||||
KEY_RESERVED, /* 0x14: VOLUME UP */
|
||||
KEY_RESERVED, /* 0x15: VOLUME DOWN */
|
||||
KEY_RESERVED, /* 0x16: MUTE */
|
||||
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
|
||||
/* (assignments unknown, please report if found) */
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
|
@ -1342,9 +1342,8 @@ static int hotkey_read(char *p)
|
|||
return len;
|
||||
}
|
||||
|
||||
res = mutex_lock_interruptible(&hotkey_mutex);
|
||||
if (res < 0)
|
||||
return res;
|
||||
if (mutex_lock_interruptible(&hotkey_mutex))
|
||||
return -ERESTARTSYS;
|
||||
res = hotkey_get(&status, &mask);
|
||||
mutex_unlock(&hotkey_mutex);
|
||||
if (res)
|
||||
|
@ -1373,9 +1372,8 @@ static int hotkey_write(char *buf)
|
|||
if (!tp_features.hotkey)
|
||||
return -ENODEV;
|
||||
|
||||
res = mutex_lock_interruptible(&hotkey_mutex);
|
||||
if (res < 0)
|
||||
return res;
|
||||
if (mutex_lock_interruptible(&hotkey_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
res = hotkey_get(&status, &mask);
|
||||
if (res)
|
||||
|
@ -3114,6 +3112,99 @@ static struct backlight_ops ibm_backlight_data = {
|
|||
|
||||
static struct mutex brightness_mutex;
|
||||
|
||||
static int __init tpacpi_query_bcll_levels(acpi_handle handle)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
int rc;
|
||||
|
||||
if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
|
||||
obj = (union acpi_object *)buffer.pointer;
|
||||
if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
|
||||
printk(IBM_ERR "Unknown BCLL data, "
|
||||
"please report this to %s\n", IBM_MAIL);
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = obj->package.count;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
kfree(buffer.pointer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
|
||||
void *context, void **rv)
|
||||
{
|
||||
char name[ACPI_PATH_SEGMENT_LENGTH];
|
||||
struct acpi_buffer buffer = { sizeof(name), &name };
|
||||
|
||||
if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
|
||||
!strncmp("BCLL", name, sizeof(name) - 1)) {
|
||||
if (tpacpi_query_bcll_levels(handle) == 16) {
|
||||
*rv = handle;
|
||||
return AE_CTRL_TERMINATE;
|
||||
} else {
|
||||
return AE_OK;
|
||||
}
|
||||
} else {
|
||||
return AE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static int __init brightness_check_levels(void)
|
||||
{
|
||||
int status;
|
||||
void *found_node = NULL;
|
||||
|
||||
if (!vid_handle) {
|
||||
IBM_ACPIHANDLE_INIT(vid);
|
||||
}
|
||||
if (!vid_handle)
|
||||
return 0;
|
||||
|
||||
/* Search for a BCLL package with 16 levels */
|
||||
status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
|
||||
brightness_find_bcll, NULL, &found_node);
|
||||
|
||||
return (ACPI_SUCCESS(status) && found_node != NULL);
|
||||
}
|
||||
|
||||
static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
|
||||
void *context, void **rv)
|
||||
{
|
||||
char name[ACPI_PATH_SEGMENT_LENGTH];
|
||||
struct acpi_buffer buffer = { sizeof(name), &name };
|
||||
|
||||
if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
|
||||
!strncmp("_BCL", name, sizeof(name) - 1)) {
|
||||
*rv = handle;
|
||||
return AE_CTRL_TERMINATE;
|
||||
} else {
|
||||
return AE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static int __init brightness_check_std_acpi_support(void)
|
||||
{
|
||||
int status;
|
||||
void *found_node = NULL;
|
||||
|
||||
if (!vid_handle) {
|
||||
IBM_ACPIHANDLE_INIT(vid);
|
||||
}
|
||||
if (!vid_handle)
|
||||
return 0;
|
||||
|
||||
/* Search for a _BCL method, but don't execute it */
|
||||
status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
|
||||
brightness_find_bcl, NULL, &found_node);
|
||||
|
||||
return (ACPI_SUCCESS(status) && found_node != NULL);
|
||||
}
|
||||
|
||||
static int __init brightness_init(struct ibm_init_struct *iibm)
|
||||
{
|
||||
int b;
|
||||
|
@ -3122,6 +3213,18 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||
|
||||
mutex_init(&brightness_mutex);
|
||||
|
||||
if (!brightness_enable) {
|
||||
dbg_printk(TPACPI_DBG_INIT,
|
||||
"brightness support disabled by module parameter\n");
|
||||
return 1;
|
||||
} else if (brightness_enable > 1) {
|
||||
if (brightness_check_std_acpi_support()) {
|
||||
printk(IBM_NOTICE
|
||||
"standard ACPI backlight interface available, not loading native one...\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!brightness_mode) {
|
||||
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
|
||||
brightness_mode = 2;
|
||||
|
@ -3135,10 +3238,17 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||
if (brightness_mode > 3)
|
||||
return -EINVAL;
|
||||
|
||||
tp_features.bright_16levels =
|
||||
thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
|
||||
brightness_check_levels();
|
||||
|
||||
b = brightness_get(NULL);
|
||||
if (b < 0)
|
||||
return 1;
|
||||
|
||||
if (tp_features.bright_16levels)
|
||||
printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n");
|
||||
|
||||
ibm_backlight_device = backlight_device_register(
|
||||
TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
|
||||
&ibm_backlight_data);
|
||||
|
@ -3148,7 +3258,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||
}
|
||||
vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
|
||||
|
||||
ibm_backlight_device->props.max_brightness = 7;
|
||||
ibm_backlight_device->props.max_brightness =
|
||||
(tp_features.bright_16levels)? 15 : 7;
|
||||
ibm_backlight_device->props.brightness = b;
|
||||
backlight_update_status(ibm_backlight_device);
|
||||
|
||||
|
@ -3167,6 +3278,8 @@ static void brightness_exit(void)
|
|||
|
||||
static int brightness_update_status(struct backlight_device *bd)
|
||||
{
|
||||
/* it is the backlight class's job (caller) to handle
|
||||
* EINTR and other errors properly */
|
||||
return brightness_set(
|
||||
(bd->props.fb_blank == FB_BLANK_UNBLANK &&
|
||||
bd->props.power == FB_BLANK_UNBLANK) ?
|
||||
|
@ -3184,13 +3297,14 @@ static int brightness_get(struct backlight_device *bd)
|
|||
if (brightness_mode & 1) {
|
||||
if (!acpi_ec_read(brightness_offset, &lec))
|
||||
return -EIO;
|
||||
lec &= 7;
|
||||
lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
|
||||
level = lec;
|
||||
};
|
||||
if (brightness_mode & 2) {
|
||||
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
|
||||
& TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
|
||||
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
|
||||
lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
|
||||
level = lcmos;
|
||||
}
|
||||
|
||||
|
@ -3206,12 +3320,13 @@ static int brightness_get(struct backlight_device *bd)
|
|||
return level;
|
||||
}
|
||||
|
||||
/* May return EINTR which can always be mapped to ERESTARTSYS */
|
||||
static int brightness_set(int value)
|
||||
{
|
||||
int cmos_cmd, inc, i, res;
|
||||
int current_value;
|
||||
|
||||
if (value > 7)
|
||||
if (value > ((tp_features.bright_16levels)? 15 : 7))
|
||||
return -EINVAL;
|
||||
|
||||
res = mutex_lock_interruptible(&brightness_mutex);
|
||||
|
@ -3227,7 +3342,7 @@ static int brightness_set(int value)
|
|||
cmos_cmd = value > current_value ?
|
||||
TP_CMOS_BRIGHTNESS_UP :
|
||||
TP_CMOS_BRIGHTNESS_DOWN;
|
||||
inc = value > current_value ? 1 : -1;
|
||||
inc = (value > current_value)? 1 : -1;
|
||||
|
||||
res = 0;
|
||||
for (i = current_value; i != value; i += inc) {
|
||||
|
@ -3256,10 +3371,11 @@ static int brightness_read(char *p)
|
|||
if ((level = brightness_get(NULL)) < 0) {
|
||||
len += sprintf(p + len, "level:\t\tunreadable\n");
|
||||
} else {
|
||||
len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
|
||||
len += sprintf(p + len, "level:\t\t%d\n", level);
|
||||
len += sprintf(p + len, "commands:\tup, down\n");
|
||||
len += sprintf(p + len, "commands:\tlevel <level>"
|
||||
" (<level> is 0-7)\n");
|
||||
" (<level> is 0-%d)\n",
|
||||
(tp_features.bright_16levels) ? 15 : 7);
|
||||
}
|
||||
|
||||
return len;
|
||||
|
@ -3268,28 +3384,34 @@ static int brightness_read(char *p)
|
|||
static int brightness_write(char *buf)
|
||||
{
|
||||
int level;
|
||||
int new_level;
|
||||
int rc;
|
||||
char *cmd;
|
||||
int max_level = (tp_features.bright_16levels) ? 15 : 7;
|
||||
|
||||
level = brightness_get(NULL);
|
||||
if (level < 0)
|
||||
return level;
|
||||
|
||||
while ((cmd = next_cmd(&buf))) {
|
||||
if ((level = brightness_get(NULL)) < 0)
|
||||
return level;
|
||||
level &= 7;
|
||||
|
||||
if (strlencmp(cmd, "up") == 0) {
|
||||
new_level = level == 7 ? 7 : level + 1;
|
||||
if (level < max_level)
|
||||
level++;
|
||||
} else if (strlencmp(cmd, "down") == 0) {
|
||||
new_level = level == 0 ? 0 : level - 1;
|
||||
} else if (sscanf(cmd, "level %d", &new_level) == 1 &&
|
||||
new_level >= 0 && new_level <= 7) {
|
||||
/* new_level set */
|
||||
if (level > 0)
|
||||
level--;
|
||||
} else if (sscanf(cmd, "level %d", &level) == 1 &&
|
||||
level >= 0 && level <= max_level) {
|
||||
/* new level set */
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
brightness_set(new_level);
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* Now we know what the final level should be, so we try to set it.
|
||||
* Doing it this way makes the syscall restartable in case of EINTR
|
||||
*/
|
||||
rc = brightness_set(level);
|
||||
return (rc == -EINTR)? ERESTARTSYS : rc;
|
||||
}
|
||||
|
||||
static struct ibm_struct brightness_driver_data = {
|
||||
|
@ -3652,9 +3774,8 @@ static ssize_t fan_pwm1_store(struct device *dev,
|
|||
/* scale down from 0-255 to 0-7 */
|
||||
newlevel = (s >> 5) & 0x07;
|
||||
|
||||
rc = mutex_lock_interruptible(&fan_mutex);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (mutex_lock_interruptible(&fan_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
rc = fan_get_status(&status);
|
||||
if (!rc && (status &
|
||||
|
@ -3904,9 +4025,8 @@ static int fan_get_status_safe(u8 *status)
|
|||
int rc;
|
||||
u8 s;
|
||||
|
||||
rc = mutex_lock_interruptible(&fan_mutex);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (mutex_lock_interruptible(&fan_mutex))
|
||||
return -ERESTARTSYS;
|
||||
rc = fan_get_status(&s);
|
||||
if (!rc)
|
||||
fan_update_desired_level(s);
|
||||
|
@ -4040,9 +4160,8 @@ static int fan_set_level_safe(int level)
|
|||
if (!fan_control_allowed)
|
||||
return -EPERM;
|
||||
|
||||
rc = mutex_lock_interruptible(&fan_mutex);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (mutex_lock_interruptible(&fan_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (level == TPACPI_FAN_LAST_LEVEL)
|
||||
level = fan_control_desired_level;
|
||||
|
@ -4063,9 +4182,8 @@ static int fan_set_enable(void)
|
|||
if (!fan_control_allowed)
|
||||
return -EPERM;
|
||||
|
||||
rc = mutex_lock_interruptible(&fan_mutex);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (mutex_lock_interruptible(&fan_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
switch (fan_control_access_mode) {
|
||||
case TPACPI_FAN_WR_ACPI_FANS:
|
||||
|
@ -4119,9 +4237,8 @@ static int fan_set_disable(void)
|
|||
if (!fan_control_allowed)
|
||||
return -EPERM;
|
||||
|
||||
rc = mutex_lock_interruptible(&fan_mutex);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (mutex_lock_interruptible(&fan_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
rc = 0;
|
||||
switch (fan_control_access_mode) {
|
||||
|
@ -4158,9 +4275,8 @@ static int fan_set_speed(int speed)
|
|||
if (!fan_control_allowed)
|
||||
return -EPERM;
|
||||
|
||||
rc = mutex_lock_interruptible(&fan_mutex);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (mutex_lock_interruptible(&fan_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
rc = 0;
|
||||
switch (fan_control_access_mode) {
|
||||
|
@ -4701,9 +4817,15 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp)
|
|||
unsigned int i;
|
||||
struct ibm_struct *ibm;
|
||||
|
||||
if (!kp || !kp->name || !val)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
|
||||
ibm = ibms_init[i].data;
|
||||
BUG_ON(ibm == NULL);
|
||||
WARN_ON(ibm == NULL);
|
||||
|
||||
if (!ibm || !ibm->name)
|
||||
continue;
|
||||
|
||||
if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
|
||||
if (strlen(val) > sizeof(ibms_init[i].param) - 2)
|
||||
|
@ -4732,6 +4854,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0);
|
|||
static int brightness_mode;
|
||||
module_param_named(brightness_mode, brightness_mode, int, 0);
|
||||
|
||||
static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
|
||||
module_param(brightness_enable, uint, 0);
|
||||
|
||||
static unsigned int hotkey_report_mode;
|
||||
module_param(hotkey_report_mode, uint, 0);
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
|
||||
/* ThinkPad CMOS NVRAM constants */
|
||||
#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
|
||||
#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
|
||||
#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f
|
||||
#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
|
||||
|
||||
#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
|
||||
|
@ -246,6 +246,7 @@ static struct {
|
|||
u32 hotkey_wlsw:1;
|
||||
u32 light:1;
|
||||
u32 light_status:1;
|
||||
u32 bright_16levels:1;
|
||||
u32 wan:1;
|
||||
u32 fan_ctrl_status_undef:1;
|
||||
u32 input_device_registered:1;
|
||||
|
@ -338,6 +339,7 @@ static int bluetooth_write(char *buf);
|
|||
static struct backlight_device *ibm_backlight_device;
|
||||
static int brightness_offset = 0x31;
|
||||
static int brightness_mode;
|
||||
static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */
|
||||
|
||||
static int brightness_init(struct ibm_init_struct *iibm);
|
||||
static void brightness_exit(void);
|
||||
|
|
|
@ -75,6 +75,7 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
|
|||
{
|
||||
int i = 0;
|
||||
int irq;
|
||||
int p, t;
|
||||
|
||||
if (!valid_IRQ(gsi))
|
||||
return;
|
||||
|
@ -85,15 +86,22 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
|
|||
if (i >= PNP_MAX_IRQ)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
if (gsi < 16 && (triggering != ACPI_EDGE_SENSITIVE ||
|
||||
polarity != ACPI_ACTIVE_HIGH)) {
|
||||
pnp_warn("BIOS BUG: legacy PNP IRQ %d should be edge trigger, "
|
||||
"active high", gsi);
|
||||
triggering = ACPI_EDGE_SENSITIVE;
|
||||
polarity = ACPI_ACTIVE_HIGH;
|
||||
/*
|
||||
* in IO-APIC mode, use overrided attribute. Two reasons:
|
||||
* 1. BIOS bug in DSDT
|
||||
* 2. BIOS uses IO-APIC mode Interrupt Source Override
|
||||
*/
|
||||
if (!acpi_get_override_irq(gsi, &t, &p)) {
|
||||
t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
|
||||
p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
|
||||
|
||||
if (triggering != t || polarity != p) {
|
||||
pnp_warn("IRQ %d override to %s, %s",
|
||||
gsi, t ? "edge":"level", p ? "low":"high");
|
||||
triggering = t;
|
||||
polarity = p;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
|
||||
res->irq_resource[i].flags |= irq_flags(triggering, polarity);
|
||||
|
|
|
@ -78,7 +78,6 @@ struct acpi_processor_cx {
|
|||
struct acpi_processor_power {
|
||||
struct cpuidle_device dev;
|
||||
struct acpi_processor_cx *state;
|
||||
struct acpi_processor_cx *bm_state;
|
||||
unsigned long bm_check_timestamp;
|
||||
u32 default_state;
|
||||
u32 bm_activity;
|
||||
|
|
|
@ -132,6 +132,11 @@ extern unsigned long acpi_realmode_flags;
|
|||
int acpi_register_gsi (u32 gsi, int triggering, int polarity);
|
||||
int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity);
|
||||
#else
|
||||
#define acpi_get_override_irq(bus, trigger, polarity) (-1)
|
||||
#endif
|
||||
/*
|
||||
* This function undoes the effect of one call to acpi_register_gsi().
|
||||
* If this matches the last registration, any IRQ resources for gsi
|
||||
|
|
|
@ -92,6 +92,7 @@ struct cpuidle_device {
|
|||
struct kobject kobj;
|
||||
struct completion kobj_unregister;
|
||||
void *governor_data;
|
||||
struct cpuidle_state *safe_state;
|
||||
};
|
||||
|
||||
DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
|
||||
|
|
Loading…
Reference in a new issue