Commit f12b12a8 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: (30 commits)
  ACPI: Kconfig text - Fix the ACPI_CONTAINER module name according to the real module name.
  eeepc-laptop: fix oops when changing backlight brightness during eeepc-laptop init
  ACPICA: Fix table entry truncation calculation
  ACPI: Enable bit 11 in _PDC to advertise hw coord
  ACPI: struct device - replace bus_id with dev_name(), dev_set_name()
  ACPI: add missing KERN_* constants to printks
  ACPI: dock: Don't eval _STA on every show_docked sysfs read
  ACPI: disable ACPI cleanly when bad RSDP found
  ACPI: delete CPU_IDLE=n code
  ACPI: cpufreq: Remove deprecated /proc/acpi/processor/../performance proc entries
  ACPI: make some IO ports off-limits to AML
  ACPICA: add debug dump of BIOS _OSI strings
  ACPI: proc_dir_entry 'video/VGA' already registered
  ACPI: Skip the first two elements in the _BCL package
  ACPI: remove BM_RLD access from idle entry path
  ACPI: remove locking from PM1x_STS register reads
  eeepc-laptop: use netlink interface
  eeepc-laptop: Implement rfkill hotplugging in eeepc-laptop
  eeepc-laptop: Check return values from rfkill_register
  eeepc-laptop: Add support for extended hotkeys
  ...
parents ccfef646 2d29c6a0
...@@ -195,19 +195,3 @@ scaling_setspeed. By "echoing" a new frequency into this ...@@ -195,19 +195,3 @@ scaling_setspeed. By "echoing" a new frequency into this
you can change the speed of the CPU, you can change the speed of the CPU,
but only within the limits of but only within the limits of
scaling_min_freq and scaling_max_freq. scaling_min_freq and scaling_max_freq.
3.2 Deprecated Interfaces
-------------------------
Depending on your kernel configuration, you might find the following
cpufreq-related files:
/proc/cpufreq
/proc/sys/cpu/*/speed
/proc/sys/cpu/*/speed-min
/proc/sys/cpu/*/speed-max
These are files for deprecated interfaces to cpufreq, which offer far
less functionality. Because of this, these interfaces aren't described
here.
...@@ -156,11 +156,11 @@ static int __init acpi_sleep_setup(char *str) ...@@ -156,11 +156,11 @@ static int __init acpi_sleep_setup(char *str)
#ifdef CONFIG_HIBERNATION #ifdef CONFIG_HIBERNATION
if (strncmp(str, "s4_nohwsig", 10) == 0) if (strncmp(str, "s4_nohwsig", 10) == 0)
acpi_no_s4_hw_signature(); acpi_no_s4_hw_signature();
if (strncmp(str, "s4_nonvs", 8) == 0)
acpi_s4_no_nvs();
#endif #endif
if (strncmp(str, "old_ordering", 12) == 0) if (strncmp(str, "old_ordering", 12) == 0)
acpi_old_suspend_ordering(); acpi_old_suspend_ordering();
if (strncmp(str, "s4_nonvs", 8) == 0)
acpi_s4_no_nvs();
str = strchr(str, ','); str = strchr(str, ',');
if (str != NULL) if (str != NULL)
str += strspn(str, ", \t"); str += strspn(str, ", \t");
......
...@@ -245,17 +245,6 @@ config X86_E_POWERSAVER ...@@ -245,17 +245,6 @@ config X86_E_POWERSAVER
comment "shared options" comment "shared options"
config X86_ACPI_CPUFREQ_PROC_INTF
bool "/proc/acpi/processor/../performance interface (deprecated)"
depends on PROC_FS
depends on X86_ACPI_CPUFREQ || X86_POWERNOW_K7_ACPI || X86_POWERNOW_K8_ACPI
help
This enables the deprecated /proc/acpi/processor/../performance
interface. While it is helpful for debugging, the generic,
cross-architecture cpufreq interfaces should be used.
If in doubt, say N.
config X86_SPEEDSTEP_LIB config X86_SPEEDSTEP_LIB
tristate tristate
default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD) default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
......
...@@ -9,6 +9,7 @@ menuconfig ACPI ...@@ -9,6 +9,7 @@ menuconfig ACPI
depends on PCI depends on PCI
depends on PM depends on PM
select PNP select PNP
select CPU_IDLE
default y default y
---help--- ---help---
Advanced Configuration and Power Interface (ACPI) support for Advanced Configuration and Power Interface (ACPI) support for
...@@ -287,7 +288,7 @@ config ACPI_CONTAINER ...@@ -287,7 +288,7 @@ config ACPI_CONTAINER
support physical cpu/memory hot-plug. support physical cpu/memory hot-plug.
If one selects "m", this driver can be loaded with If one selects "m", this driver can be loaded with
"modprobe acpi_container". "modprobe container".
config ACPI_HOTPLUG_MEMORY config ACPI_HOTPLUG_MEMORY
tristate "Memory Hotplug" tristate "Memory Hotplug"
......
...@@ -538,10 +538,9 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) ...@@ -538,10 +538,9 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO, ACPI_WARNING((AE_INFO,
"Truncating %u table entries!", "Truncating %u table entries!",
(unsigned) (unsigned) (table_count -
(acpi_gbl_root_table_list.size - (acpi_gbl_root_table_list.
acpi_gbl_root_table_list. count - 2))));
count)));
break; break;
} }
} }
......
...@@ -116,9 +116,9 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) ...@@ -116,9 +116,9 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
return_ACPI_STATUS(AE_NO_MEMORY); return_ACPI_STATUS(AE_NO_MEMORY);
} }
/* Default return value is SUPPORTED */ /* Default return value is 0, NOT-SUPPORTED */
return_desc->integer.value = ACPI_UINT32_MAX; return_desc->integer.value = 0;
walk_state->return_desc = return_desc; walk_state->return_desc = return_desc;
/* Compare input string to static table of supported interfaces */ /* Compare input string to static table of supported interfaces */
...@@ -127,10 +127,8 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) ...@@ -127,10 +127,8 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
if (!ACPI_STRCMP if (!ACPI_STRCMP
(string_desc->string.pointer, (string_desc->string.pointer,
acpi_interfaces_supported[i])) { acpi_interfaces_supported[i])) {
return_desc->integer.value = ACPI_UINT32_MAX;
/* The interface is supported */ goto done;
return_ACPI_STATUS(AE_OK);
} }
} }
...@@ -141,15 +139,14 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) ...@@ -141,15 +139,14 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
*/ */
status = acpi_os_validate_interface(string_desc->string.pointer); status = acpi_os_validate_interface(string_desc->string.pointer);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
return_desc->integer.value = ACPI_UINT32_MAX;
/* The interface is supported */
return_ACPI_STATUS(AE_OK);
} }
/* The interface is not supported */ done:
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, "ACPI: BIOS _OSI(%s) %ssupported\n",
string_desc->string.pointer,
return_desc->integer.value == 0 ? "not-" : ""));
return_desc->integer.value = 0;
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
} }
......
...@@ -163,7 +163,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) ...@@ -163,7 +163,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
/* Fall through */ /* Fall through */
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
printk("Container driver received %s event\n", printk(KERN_WARNING "Container driver received %s event\n",
(type == ACPI_NOTIFY_BUS_CHECK) ? (type == ACPI_NOTIFY_BUS_CHECK) ?
"ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"); "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
status = acpi_bus_get_device(handle, &device); status = acpi_bus_get_device(handle, &device);
...@@ -174,7 +174,8 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) ...@@ -174,7 +174,8 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
kobject_uevent(&device->dev.kobj, kobject_uevent(&device->dev.kobj,
KOBJ_ONLINE); KOBJ_ONLINE);
else else
printk("Failed to add container\n"); printk(KERN_WARNING
"Failed to add container\n");
} }
} else { } else {
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
......
...@@ -855,10 +855,14 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -855,10 +855,14 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
static ssize_t show_docked(struct device *dev, static ssize_t show_docked(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct acpi_device *tmp;
struct dock_station *dock_station = *((struct dock_station **) struct dock_station *dock_station = *((struct dock_station **)
dev->platform_data); dev->platform_data);
return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
return snprintf(buf, PAGE_SIZE, "1\n");
return snprintf(buf, PAGE_SIZE, "0\n");
} }
static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
...@@ -984,7 +988,7 @@ static int dock_add(acpi_handle handle) ...@@ -984,7 +988,7 @@ static int dock_add(acpi_handle handle)
ret = device_create_file(&dock_device->dev, &dev_attr_docked); ret = device_create_file(&dock_device->dev, &dev_attr_docked);
if (ret) { if (ret) {
printk("Error %d adding sysfs file\n", ret); printk(KERN_ERR "Error %d adding sysfs file\n", ret);
platform_device_unregister(dock_device); platform_device_unregister(dock_device);
kfree(dock_station); kfree(dock_station);
dock_station = NULL; dock_station = NULL;
...@@ -992,7 +996,7 @@ static int dock_add(acpi_handle handle) ...@@ -992,7 +996,7 @@ static int dock_add(acpi_handle handle)
} }
ret = device_create_file(&dock_device->dev, &dev_attr_undock); ret = device_create_file(&dock_device->dev, &dev_attr_undock);
if (ret) { if (ret) {
printk("Error %d adding sysfs file\n", ret); printk(KERN_ERR "Error %d adding sysfs file\n", ret);
device_remove_file(&dock_device->dev, &dev_attr_docked); device_remove_file(&dock_device->dev, &dev_attr_docked);
platform_device_unregister(dock_device); platform_device_unregister(dock_device);
kfree(dock_station); kfree(dock_station);
...@@ -1001,7 +1005,7 @@ static int dock_add(acpi_handle handle) ...@@ -1001,7 +1005,7 @@ static int dock_add(acpi_handle handle)
} }
ret = device_create_file(&dock_device->dev, &dev_attr_uid); ret = device_create_file(&dock_device->dev, &dev_attr_uid);
if (ret) { if (ret) {
printk("Error %d adding sysfs file\n", ret); printk(KERN_ERR "Error %d adding sysfs file\n", ret);
device_remove_file(&dock_device->dev, &dev_attr_docked); device_remove_file(&dock_device->dev, &dev_attr_docked);
device_remove_file(&dock_device->dev, &dev_attr_undock); device_remove_file(&dock_device->dev, &dev_attr_undock);
platform_device_unregister(dock_device); platform_device_unregister(dock_device);
...@@ -1011,7 +1015,7 @@ static int dock_add(acpi_handle handle) ...@@ -1011,7 +1015,7 @@ static int dock_add(acpi_handle handle)
} }
ret = device_create_file(&dock_device->dev, &dev_attr_flags); ret = device_create_file(&dock_device->dev, &dev_attr_flags);
if (ret) { if (ret) {
printk("Error %d adding sysfs file\n", ret); printk(KERN_ERR "Error %d adding sysfs file\n", ret);
device_remove_file(&dock_device->dev, &dev_attr_docked); device_remove_file(&dock_device->dev, &dev_attr_docked);
device_remove_file(&dock_device->dev, &dev_attr_undock); device_remove_file(&dock_device->dev, &dev_attr_undock);
device_remove_file(&dock_device->dev, &dev_attr_uid); device_remove_file(&dock_device->dev, &dev_attr_uid);
......
...@@ -982,7 +982,7 @@ int __init acpi_ec_ecdt_probe(void) ...@@ -982,7 +982,7 @@ int __init acpi_ec_ecdt_probe(void)
saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!saved_ec) if (!saved_ec)
return -ENOMEM; return -ENOMEM;
memcpy(&saved_ec, boot_ec, sizeof(saved_ec)); memcpy(saved_ec, boot_ec, sizeof(*saved_ec));
/* fall through */ /* fall through */
} }
/* This workaround is needed only on some broken machines, /* This workaround is needed only on some broken machines,
......
...@@ -255,12 +255,12 @@ static int acpi_platform_notify(struct device *dev) ...@@ -255,12 +255,12 @@ static int acpi_platform_notify(struct device *dev)
} }
type = acpi_get_bus_type(dev->bus); type = acpi_get_bus_type(dev->bus);
if (!type) { if (!type) {
DBG("No ACPI bus support for %s\n", dev->bus_id); DBG("No ACPI bus support for %s\n", dev_name(dev));
ret = -EINVAL; ret = -EINVAL;
goto end; goto end;
} }
if ((ret = type->find_device(dev, &handle)) != 0) if ((ret = type->find_device(dev, &handle)) != 0)
DBG("Can't get handler for %s\n", dev->bus_id); DBG("Can't get handler for %s\n", dev_name(dev));
end: end:
if (!ret) if (!ret)
acpi_bind_one(dev, handle); acpi_bind_one(dev, handle);
...@@ -271,10 +271,10 @@ static int acpi_platform_notify(struct device *dev) ...@@ -271,10 +271,10 @@ static int acpi_platform_notify(struct device *dev)
acpi_get_name(dev->archdata.acpi_handle, acpi_get_name(dev->archdata.acpi_handle,
ACPI_FULL_PATHNAME, &buffer); ACPI_FULL_PATHNAME, &buffer);
DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
kfree(buffer.pointer); kfree(buffer.pointer);
} else } else
DBG("Device %s -> No ACPI support\n", dev->bus_id); DBG("Device %s -> No ACPI support\n", dev_name(dev));
#endif #endif
return ret; return ret;
......
...@@ -228,10 +228,10 @@ void acpi_os_vprintf(const char *fmt, va_list args) ...@@ -228,10 +228,10 @@ void acpi_os_vprintf(const char *fmt, va_list args)
if (acpi_in_debugger) { if (acpi_in_debugger) {
kdb_printf("%s", buffer); kdb_printf("%s", buffer);
} else { } else {
printk("%s", buffer); printk(KERN_CONT "%s", buffer);
} }
#else #else
printk("%s", buffer); printk(KERN_CONT "%s", buffer);
#endif #endif
} }
...@@ -1317,6 +1317,54 @@ acpi_os_validate_interface (char *interface) ...@@ -1317,6 +1317,54 @@ acpi_os_validate_interface (char *interface)
return AE_SUPPORT; return AE_SUPPORT;
} }
#ifdef CONFIG_X86
struct aml_port_desc {
uint start;
uint end;
char* name;
char warned;
};
static struct aml_port_desc aml_invalid_port_list[] = {
{0x20, 0x21, "PIC0", 0},
{0xA0, 0xA1, "PIC1", 0},
{0x4D0, 0x4D1, "ELCR", 0}
};
/*
* valid_aml_io_address()
*
* if valid, return true
* else invalid, warn once, return false
*/
static bool valid_aml_io_address(uint address, uint length)
{
int i;
int entries = sizeof(aml_invalid_port_list) / sizeof(struct aml_port_desc);
for (i = 0; i < entries; ++i) {
if ((address >= aml_invalid_port_list[i].start &&
address <= aml_invalid_port_list[i].end) ||
(address + length >= aml_invalid_port_list[i].start &&
address + length <= aml_invalid_port_list[i].end))
{
if (!aml_invalid_port_list[i].warned)
{
printk(KERN_ERR "ACPI: Denied BIOS AML access"
" to invalid port 0x%x+0x%x (%s)\n",
address, length,
aml_invalid_port_list[i].name);
aml_invalid_port_list[i].warned = 1;
}
return false; /* invalid */
}
}
return true; /* valid */
}
#else
static inline bool valid_aml_io_address(uint address, uint length) { return true; }
#endif
/****************************************************************************** /******************************************************************************
* *
* FUNCTION: acpi_os_validate_address * FUNCTION: acpi_os_validate_address
...@@ -1346,6 +1394,8 @@ acpi_os_validate_address ( ...@@ -1346,6 +1394,8 @@ acpi_os_validate_address (
switch (space_id) { switch (space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO: case ACPI_ADR_SPACE_SYSTEM_IO:
if (!valid_aml_io_address(address, length))
return AE_AML_ILLEGAL_ADDRESS;
case ACPI_ADR_SPACE_SYSTEM_MEMORY: case ACPI_ADR_SPACE_SYSTEM_MEMORY:
/* Only interference checks against SystemIO and SytemMemory /* Only interference checks against SystemIO and SytemMemory
are needed */ are needed */
......
...@@ -593,7 +593,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) ...@@ -593,7 +593,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
return -ENODEV; return -ENODEV;
} else { } else {
acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
printk(PREFIX "%s [%s] enabled at IRQ %d\n", printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
acpi_device_name(link->device), acpi_device_name(link->device),
acpi_device_bid(link->device), link->irq.active); acpi_device_bid(link->device), link->irq.active);
} }
......
...@@ -66,43 +66,17 @@ ACPI_MODULE_NAME("processor_idle"); ...@@ -66,43 +66,17 @@ ACPI_MODULE_NAME("processor_idle");
#define ACPI_PROCESSOR_FILE_POWER "power" #define ACPI_PROCESSOR_FILE_POWER "power"
#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000) #define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
#define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY) #define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY)
#ifndef CONFIG_CPU_IDLE
#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
static void (*pm_idle_save) (void) __read_mostly;
#else
#define C2_OVERHEAD 1 /* 1us */ #define C2_OVERHEAD 1 /* 1us */
#define C3_OVERHEAD 1 /* 1us */ #define C3_OVERHEAD 1 /* 1us */
#endif
#define PM_TIMER_TICKS_TO_US(p) (((p) * 1000)/(PM_TIMER_FREQUENCY/1000)) #define PM_TIMER_TICKS_TO_US(p) (((p) * 1000)/(PM_TIMER_FREQUENCY/1000))
static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER; static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;
#ifdef CONFIG_CPU_IDLE
module_param(max_cstate, uint, 0000); module_param(max_cstate, uint, 0000);
#else
module_param(max_cstate, uint, 0644);
#endif
static unsigned int nocst __read_mostly; static unsigned int nocst __read_mostly;
module_param(nocst, uint, 0000); module_param(nocst, uint, 0000);
#ifndef CONFIG_CPU_IDLE
/*
* bm_history -- bit-mask with a bit per jiffy of bus-master activity
* 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms
* 800 HZ: 0xFFFFFFFF: 32 jiffies = 40ms
* 100 HZ: 0x0000000F: 4 jiffies = 40ms
* reduce history for more aggressive entry into C3
*/
static unsigned int bm_history __read_mostly =
(HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1));
module_param(bm_history, uint, 0644);
static int acpi_processor_set_power_policy(struct acpi_processor *pr);
#else /* CONFIG_CPU_IDLE */
static unsigned int latency_factor __read_mostly = 2; static unsigned int latency_factor __read_mostly = 2;
module_param(latency_factor, uint, 0644); module_param(latency_factor, uint, 0644);
#endif
/* /*
* IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
...@@ -224,71 +198,6 @@ static void acpi_safe_halt(void) ...@@ -224,71 +198,6 @@ static void acpi_safe_halt(void)
current_thread_info()->status |= TS_POLLING; current_thread_info()->status |= TS_POLLING;
} }
#ifndef CONFIG_CPU_IDLE
static void
acpi_processor_power_activate(struct acpi_processor *pr,
struct acpi_processor_cx *new)
{
struct acpi_processor_cx *old;
if (!pr || !new)
return;
old = pr->power.state;
if (old)
old->promotion.count = 0;
new->demotion.count = 0;
/* Cleanup from old state. */
if (old) {
switch (old->type) {
case ACPI_STATE_C3:
/* Disable bus master reload */
if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
break;
}
}
/* Prepare to use new state. */
switch (new->type) {
case ACPI_STATE_C3:
/* Enable bus master reload */
if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
break;
}
pr->power.state = new;
return;
}
static atomic_t c3_cpu_count;
/* Common C-state entry for C2, C3, .. */
static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
{
/* Don't trace irqs off for idle */
stop_critical_timings();
if (cstate->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cstate);
} else {
int unused;
/* IO port based C-state */
inb(cstate->address);
/* Dummy wait op - must do something useless after P_LVL2 read
because chipsets cannot guarantee that STPCLK# signal
gets asserted in time to freeze execution properly. */
unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
}
start_critical_timings();
}
#endif /* !CONFIG_CPU_IDLE */
#ifdef ARCH_APICTIMER_STOPS_ON_C3 #ifdef ARCH_APICTIMER_STOPS_ON_C3
/* /*
...@@ -390,421 +299,6 @@ static int tsc_halts_in_c(int state) ...@@ -390,421 +299,6 @@ static int tsc_halts_in_c(int state)
} }
#endif #endif
#ifndef CONFIG_CPU_IDLE
static void acpi_processor_idle(void)
{
struct acpi_processor *pr = NULL;
struct acpi_processor_cx *cx = NULL;
struct acpi_processor_cx *next_state = NULL;
int sleep_ticks = 0;
u32 t1, t2 = 0;
/*
* Interrupts must be disabled during bus mastering calculations and
* for C2/C3 transitions.
*/
local_irq_disable();
pr = __get_cpu_var(processors);
if (!pr) {
local_irq_enable();
return;
}
/*
* Check whether we truly need to go idle, or should
* reschedule:
*/
if (unlikely(need_resched())) {
local_irq_enable();
return;
}
cx = pr->power.state;
if (!cx || acpi_idle_suspend) {
if (pm_idle_save) {
pm_idle_save(); /* enables IRQs */
} else {
acpi_safe_halt();
local_irq_enable();
}
return;
}
/*
* Check BM Activity
* -----------------
* Check for bus mastering activity (if required), record, and check
* for demotion.
*/
if (pr->flags.bm_check) {
u32 bm_status = 0;
unsigned long diff = jiffies - pr->power.bm_check_timestamp;
if (diff > 31)
diff = 31;
pr->power.bm_activity <<= diff;
acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
if (bm_status) {
pr->power.bm_activity |= 0x1;
acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
}
/*
* PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
* the true state of bus mastering activity; forcing us to
* manually check the BMIDEA bit of each IDE channel.
*/
else if (errata.piix4.bmisx) {
if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
|| (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
pr->power.bm_activity |= 0x1;
}
pr->power.bm_check_timestamp = jiffies;
/*
* If bus mastering is or was active this jiffy, demote
* to avoid a faulty transition. Note that the processor
* won't enter a low-power state during this call (to this
* function) but should upon the next.
*
* TBD: A better policy might be to fallback to the demotion
* state (use it for this quantum only) istead of
* demoting -- and rely on duration as our sole demotion
* qualification. This may, however, introduce DMA
* issues (e.g. floppy DMA transfer overrun/underrun).
*/
if ((pr->power.bm_activity & 0x1) &&
cx->demotion.threshold.bm) {
local_irq_enable();
next_state = cx->demotion.state;
goto end;
}
}
#ifdef CONFIG_HOTPLUG_CPU
/*
* Check for P_LVL2_UP flag before entering C2 and above on
* an SMP system. We do it here instead of doing it at _CST/P_LVL
* detection phase, to work cleanly with logical CPU hotplug.
*/
if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
!pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
cx = &pr->power.states[ACPI_STATE_C1];
#endif
/*
* Sleep:
* ------
* Invoke the current Cx state to put the processor to sleep.
*/
if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) {
current_thread_info()->status &= ~TS_POLLING;
/*
* TS_POLLING-cleared state must be visible before we
* test NEED_RESCHED:
*/
smp_mb();
if (need_resched()) {
current_thread_info()->status |= TS_POLLING;
local_irq_enable();
return;
}
}
switch (cx->type) {
case ACPI_STATE_C1:
/*
* Invoke C1.
* Use the appropriate idle routine, the one that would
* be used without acpi C-states.
*/
if (pm_idle_save) {
pm_idle_save(); /* enables IRQs */
} else {
acpi_safe_halt();
local_irq_enable();
}
/*
* TBD: Can't get time duration while in C1, as resumes
* go to an ISR rather than here. Need to instrument
* base interrupt handler.
*
* Note: the TSC better not stop in C1, sched_clock() will
* skew otherwise.
*/
sleep_ticks = 0xFFFFFFFF;
break;
case ACPI_STATE_C2:
/* Get start time (ticks) */
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Tell the scheduler that we are going deep-idle: */
sched_clock_idle_sleep_event();
/* Invoke C2 */
acpi_state_timer_broadcast(pr, cx, 1);
acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
/* TSC halts in C2, so notify users */
if (tsc_halts_in_c(ACPI_STATE_C2))
mark_tsc_unstable("possible TSC halt in C2");
#endif
/* Compute time (ticks) that we were actually asleep */
sleep_ticks = ticks_elapsed(t1, t2);
/* Tell the scheduler how much we idled: */
sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
/* Re-enable interrupts */
local_irq_enable();
/* Do not account our idle-switching overhead: */
sleep_ticks -= cx->latency_ticks + C2_OVERHEAD;
current_thread_info()->status |= TS_POLLING;
acpi_state_timer_broadcast(pr, cx, 0);
break;
case ACPI_STATE_C3:
acpi_unlazy_tlb(smp_processor_id());
/*
* Must be done before busmaster disable as we might
* need to access HPET !
*/
acpi_state_timer_broadcast(pr, cx, 1);
/*
* 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) {
if (atomic_inc_return(&c3_cpu_count) ==
num_online_cpus()) {
/*
* All CPUs are trying to go to C3
* Disable bus master arbitration
*/
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
}
} else if (!pr->flags.bm_check) {
/* SMP with no shared cache... Invalidate cache */
ACPI_FLUSH_CPU_CACHE();
}
/* Get start time (ticks) */
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C3 */
/* Tell the scheduler that we are going deep-idle: */
sched_clock_idle_sleep_event();
acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
if (pr->flags.bm_check && pr->flags.bm_control) {
/* Enable bus master arbitration */
atomic_dec(&c3_cpu_count);
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
/* TSC halts in C3, so notify users */
if (tsc_halts_in_c(ACPI_STATE_C3))
mark_tsc_unstable("TSC halts in C3");
#endif
/* Compute time (ticks) that we were actually asleep */
sleep_ticks = ticks_elapsed(t1, t2);
/* Tell the scheduler how much we idled: */
sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
/* Re-enable interrupts */
local_irq_enable();
/* Do not account our idle-switching overhead: */
sleep_ticks -= cx->latency_ticks + C3_OVERHEAD;
current_thread_info()->status |= TS_POLLING;
acpi_state_timer_broadcast(pr, cx, 0);
break;
default:
local_irq_enable();
return;
}
cx->usage++;
if ((cx->type != ACPI_STATE_C1) && (sleep_ticks > 0))
cx->time += sleep_ticks;
next_state = pr->power.state;
#ifdef CONFIG_HOTPLUG_CPU
/* Don't do promotion/demotion */
if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) &&
!pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) {
next_state = cx;
goto end;
}
#endif
/*
* Promotion?
* ----------
* Track the number of longs (time asleep is greater than threshold)
* and promote when the count threshold is reached. Note that bus
* mastering activity may prevent promotions.
* Do not promote above max_cstate.
*/
if (cx->promotion.state &&
((cx->promotion.state - pr->power.states) <= max_cstate)) {
if (sleep_ticks > cx->promotion.threshold.ticks &&
cx->promotion.state->latency <=
pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
cx->promotion.count++;
cx->demotion.count = 0;
if (cx->promotion.count >=
cx->promotion.threshold.count) {
if (pr->flags.bm_check) {
if (!
(pr->power.bm_activity & cx->
promotion.threshold.bm)) {
next_state =
cx->promotion.state;
goto end;
}
} else {
next_state = cx->promotion.state;
goto end;
}
}
}
}
/*
* Demotion?
* ---------
* Track the number of shorts (time asleep is less than time threshold)
* and demote when the usage threshold is reached.
*/
if (cx->demotion.state) {
if (sleep_ticks < cx->demotion.threshold.ticks) {
cx->demotion.count++;
cx->promotion.count = 0;
if (cx->demotion.count >= cx->demotion.threshold.count) {
next_state = cx->demotion.state;
goto end;
}
}
}
end:
/*
* Demote if current state exceeds max_cstate
* or if the latency of the current state is unacceptable
*/
if ((pr->power.state - pr->power.states) > max_cstate ||
pr->power.state->latency >
pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
if (cx->demotion.state)
next_state = cx->demotion.state;
}
/*
* New Cx State?
* -------------
* If we're going to start using a new Cx state we must clean up
* from the previous and prepare to use the new.
*/
if (next_state != pr->power.state)
acpi_processor_power_activate(pr, next_state);
}
static int acpi_processor_set_power_policy(struct acpi_processor *pr)
{
unsigned int i;
unsigned int state_is_set = 0;
struct acpi_processor_cx *lower = NULL;
struct acpi_processor_cx *higher = NULL;
struct acpi_processor_cx *cx;
if (!pr)
return -EINVAL;
/*
* This function sets the default Cx state policy (OS idle handler).
* Our scheme is to promote quickly to C2 but more conservatively
* to C3. We're favoring C2 for its characteristics of low latency
* (quick response), good power savings, and ability to allow bus
* mastering activity. Note that the Cx state policy is completely
* customizable and can be altered dynamically.
*/
/* startup state */
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
cx = &pr->power.states[i];
if (!cx->valid)
continue;
if (!state_is_set)
pr->power.state = cx;
state_is_set++;
break;
}
if (!state_is_set)
return -ENODEV;
/* demotion */
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
cx = &pr->power.states[i];
if (!cx->valid)
continue;
if (lower) {
cx->demotion.state = lower;
cx->demotion.threshold.ticks = cx->latency_ticks;
cx->demotion.threshold.count = 1;
if (cx->type == ACPI_STATE_C3)
cx->demotion.threshold.bm = bm_history;
}
lower = cx;
}
/* promotion */
for (i = (ACPI_PROCESSOR_MAX_POWER - 1); i > 0; i--) {
cx = &pr->power.states[i];
if (!cx->valid)
continue;
if (higher) {
cx->promotion.state = higher;
cx->promotion.threshold.ticks = cx->latency_ticks;
if (cx->type >= ACPI_STATE_C2)
cx->promotion.threshold.count = 4;
else
cx->promotion.threshold.count = 10;
if (higher->type == ACPI_STATE_C3)
cx->promotion.threshold.bm = bm_history;
}
higher = cx;
}
return 0;
}
#endif /* !CONFIG_CPU_IDLE */
static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
{ {
...@@ -1047,11 +541,7 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) ...@@ -1047,11 +541,7 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
*/ */
cx->valid = 1; cx->valid = 1;
#ifndef CONFIG_CPU_IDLE
cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
#else
cx->latency_ticks = cx->latency; cx->latency_ticks = cx->latency;
#endif
return; return;
} }
...@@ -1121,7 +611,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, ...@@ -1121,7 +611,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
" for C3 to be enabled on SMP systems\n")); " for C3 to be enabled on SMP systems\n"));
return; return;
} }
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
} }
/* /*
...@@ -1132,11 +621,16 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, ...@@ -1132,11 +621,16 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
*/ */
cx->valid = 1; cx->valid = 1;
#ifndef CONFIG_CPU_IDLE
cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
#else
cx->latency_ticks = cx->latency; cx->latency_ticks = cx->latency;
#endif /*
* On older chipsets, BM_RLD needs to be set
* in order for Bus Master activity to wake the
* system from C3. Newer chipsets handle DMA
* during C3 automatically and BM_RLD is a NOP.
* In either case, the proper way to
* handle BM_RLD is to set it and leave it set.
*/
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
return; return;
} }
...@@ -1201,20 +695,6 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) ...@@ -1201,20 +695,6 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
pr->power.count = acpi_processor_power_verify(pr); pr->power.count = acpi_processor_power_verify(pr);
#ifndef CONFIG_CPU_IDLE
/*
* Set Default Policy
* ------------------
* Now that we know which states are supported, set the default
* policy. Note that this policy can be changed dynamically
* (e.g. encourage deeper sleeps to conserve battery life when
* not on AC).
*/
result = acpi_processor_set_power_policy(pr);
if (result)
return result;
#endif
/* /*
* if one state of type C2 or C3 is available, mark this * if one state of type C2 or C3 is available, mark this
* CPU as being "idle manageable" * CPU as being "idle manageable"
...@@ -1312,69 +792,6 @@ static const struct file_operations acpi_processor_power_fops = { ...@@ -1312,69 +792,6 @@ static const struct file_operations acpi_processor_power_fops = {
.release = single_release, .release = single_release,
}; };
#ifndef CONFIG_CPU_IDLE
int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int result = 0;
if (boot_option_idle_override)
return 0;
if (!pr)
return -EINVAL;
if (nocst) {
return -ENODEV;
}
if (!pr->flags.power_setup_done)
return -ENODEV;
/*
* Fall back to the default idle loop, when pm_idle_save had
* been initialized.
*/
if (pm_idle_save) {
pm_idle = pm_idle_save;
/* Relies on interrupts forcing exit from idle. */
synchronize_sched();
}
pr->flags.power = 0;
result = acpi_processor_get_power_info(pr);
if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
pm_idle = acpi_processor_idle;
return result;
}
#ifdef CONFIG_SMP
static void smp_callback(void *v)
{
/* we already woke the CPU up, nothing more to do */
}
/*
* This function gets called when a part of the kernel has a new latency
* requirement. This means we need to get all processors out of their C-state,
* and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
* wakes them all right up.
*/
static int acpi_processor_latency_notify(struct notifier_block *b,
unsigned long l, void *v)
{
smp_call_function(smp_callback, NULL, 1);
return NOTIFY_OK;
}
static struct notifier_block acpi_processor_latency_notifier = {
.notifier_call = acpi_processor_latency_notify,
};
#endif
#else /* CONFIG_CPU_IDLE */
/** /**
* acpi_idle_bm_check - checks if bus master activity was detected * acpi_idle_bm_check - checks if bus master activity was detected
...@@ -1383,7 +800,7 @@ static int acpi_idle_bm_check(void) ...@@ -1383,7 +800,7 @@ static int acpi_idle_bm_check(void)
{ {
u32 bm_status = 0; u32 bm_status = 0;
acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); acpi_get_register_unlocked(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
if (bm_status) if (bm_status)
acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
/* /*
...@@ -1399,25 +816,6 @@ static int acpi_idle_bm_check(void) ...@@ -1399,25 +816,6 @@ static int acpi_idle_bm_check(void)
return bm_status; return bm_status;
} }
/**
* acpi_idle_update_bm_rld - updates the BM_RLD bit depending on target state
* @pr: the processor
* @target: the new target state
*/
static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
struct acpi_processor_cx *target)
{
if (pr->flags.bm_rld_set && target->type != ACPI_STATE_C3) {
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
pr->flags.bm_rld_set = 0;
}
if (!pr->flags.bm_rld_set && target->type == ACPI_STATE_C3) {
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
pr->flags.bm_rld_set = 1;
}
}
/** /**
* acpi_idle_do_entry - a helper function that does C2 and C3 type entry * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
* @cx: cstate data * @cx: cstate data
...@@ -1473,9 +871,6 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, ...@@ -1473,9 +871,6 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
return 0; return 0;
} }
if (pr->flags.bm_check)
acpi_idle_update_bm_rld(pr, cx);
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
acpi_idle_do_entry(cx); acpi_idle_do_entry(cx);
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
...@@ -1527,9 +922,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, ...@@ -1527,9 +922,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
*/ */
acpi_state_timer_broadcast(pr, cx, 1); acpi_state_timer_broadcast(pr, cx, 1);
if (pr->flags.bm_check)
acpi_idle_update_bm_rld(pr, cx);
if (cx->type == ACPI_STATE_C3) if (cx->type == ACPI_STATE_C3)
ACPI_FLUSH_CPU_CACHE(); ACPI_FLUSH_CPU_CACHE();
...@@ -1621,8 +1013,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, ...@@ -1621,8 +1013,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
*/ */
acpi_state_timer_broadcast(pr, cx, 1); acpi_state_timer_broadcast(pr, cx, 1);
acpi_idle_update_bm_rld(pr, cx);
/* /*
* disable bus master * disable bus master
* bm_check implies we need ARB_DIS * bm_check implies we need ARB_DIS
...@@ -1795,8 +1185,6 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) ...@@ -1795,8 +1185,6 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
return ret; return ret;
} }
#endif /* CONFIG_CPU_IDLE */
int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device) struct acpi_device *device)
{ {
...@@ -1825,10 +1213,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, ...@@ -1825,10 +1213,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
"ACPI: processor limited to max C-state %d\n", "ACPI: processor limited to max C-state %d\n",
max_cstate); max_cstate);
first_run++; first_run++;
#if !defined(CONFIG_CPU_IDLE) && defined(CONFIG_SMP)
pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY,
&acpi_processor_latency_notifier);
#endif
} }
if (!pr) if (!pr)
...@@ -1852,11 +1236,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, ...@@ -1852,11 +1236,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
* platforms that only support C1. * platforms that only support C1.
*/ */
if (pr->flags.power) { if (pr->flags.power) {
#ifdef CONFIG_CPU_IDLE
acpi_processor_setup_cpuidle(pr); acpi_processor_setup_cpuidle(pr);
if (cpuidle_register_device(&pr->power.dev)) if (cpuidle_register_device(&pr->power.dev))
return -EIO; return -EIO;
#endif
printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id); printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id);
for (i = 1; i <= pr->power.count; i++) for (i = 1; i <= pr->power.count; i++)
...@@ -1864,13 +1246,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, ...@@ -1864,13 +1246,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
printk(" C%d[C%d]", i, printk(" C%d[C%d]", i,
pr->power.states[i].type); pr->power.states[i].type);
printk(")\n"); printk(")\n");
#ifndef CONFIG_CPU_IDLE
if (pr->id == 0) {
pm_idle_save = pm_idle;
pm_idle = acpi_processor_idle;
}
#endif
} }
/* 'power' [R] */ /* 'power' [R] */
...@@ -1889,34 +1264,12 @@ int acpi_processor_power_exit(struct acpi_processor *pr, ...@@ -1889,34 +1264,12 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
if (boot_option_idle_override) if (boot_option_idle_override)
return 0; return 0;
#ifdef CONFIG_CPU_IDLE
cpuidle_unregister_device(&pr->power.dev); cpuidle_unregister_device(&pr->power.dev);
#endif
pr->flags.power_setup_done = 0; pr->flags.power_setup_done = 0;
if (acpi_device_dir(device)) if (acpi_device_dir(device))
remove_proc_entry(ACPI_PROCESSOR_FILE_POWER, remove_proc_entry(ACPI_PROCESSOR_FILE_POWER,
acpi_device_dir(device)); acpi_device_dir(device));
#ifndef CONFIG_CPU_IDLE
/* Unregister the idle handler when processor #0 is removed. */
if (pr->id == 0) {
if (pm_idle_save)
pm_idle = pm_idle_save;
/*
* We are about to unload the current idle thread pm callback
* (pm_idle), Wait for all processors to update cached/local
* copies of pm_idle before proceeding.
*/
cpu_idle_wait();
#ifdef CONFIG_SMP
pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY,
&acpi_processor_latency_notifier);
#endif
}
#endif
return 0; return 0;
} }
...@@ -31,14 +31,6 @@ ...@@ -31,14 +31,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#endif
#ifdef CONFIG_X86 #ifdef CONFIG_X86
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#endif #endif
...@@ -434,96 +426,6 @@ int acpi_processor_notify_smm(struct module *calling_module) ...@@ -434,96 +426,6 @@ int acpi_processor_notify_smm(struct module *calling_module)
EXPORT_SYMBOL(acpi_processor_notify_smm); EXPORT_SYMBOL(acpi_processor_notify_smm);
#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
/* /proc/acpi/processor/../performance interface (DEPRECATED) */
static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_processor_perf_fops = {
.owner = THIS_MODULE,
.open = acpi_processor_perf_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = seq->private;
int i;
if (!pr)
goto end;
if (!pr->performance) {
seq_puts(seq, "<not supported>\n");
goto end;
}
seq_printf(seq, "state count: %d\n"
"active state: P%d\n",
pr->performance->state_count, pr->performance->state);
seq_puts(seq, "states:\n");
for (i = 0; i < pr->performance->state_count; i++)
seq_printf(seq,
" %cP%d: %d MHz, %d mW, %d uS\n",
(i == pr->performance->state ? '*' : ' '), i,
(u32) pr->performance->states[i].core_frequency,
(u32) pr->performance->states[i].power,
(u32) pr->performance->states[i].transition_latency);
end:
return 0;
}
static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_processor_perf_seq_show,
PDE(inode)->data);
}
static void acpi_cpufreq_add_file(struct acpi_processor *pr)
{
struct acpi_device *device = NULL;
if (acpi_bus_get_device(pr->handle, &device))
return;
/* add file 'performance' [R/W] */
proc_create_data(ACPI_PROCESSOR_FILE_PERFORMANCE, S_IFREG | S_IRUGO,
acpi_device_dir(device),
&acpi_processor_perf_fops, acpi_driver_data(device));
return;
}
static void acpi_cpufreq_remove_file(struct acpi_processor *pr)
{
struct acpi_device *device = NULL;
if (acpi_bus_get_device(pr->handle, &device))
return;
/* remove file 'performance' */
remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
acpi_device_dir(device));
return;
}
#else
static void acpi_cpufreq_add_file(struct acpi_processor *pr)
{
return;
}
static void acpi_cpufreq_remove_file(struct acpi_processor *pr)
{
return;
}
#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
static int acpi_processor_get_psd(struct acpi_processor *pr) static int acpi_processor_get_psd(struct acpi_processor *pr)
{ {
int result = 0; int result = 0;
...@@ -747,14 +649,12 @@ int acpi_processor_preregister_performance( ...@@ -747,14 +649,12 @@ int acpi_processor_preregister_performance(
} }
EXPORT_SYMBOL(acpi_processor_preregister_performance); EXPORT_SYMBOL(acpi_processor_preregister_performance);
int int
acpi_processor_register_performance(struct acpi_processor_performance acpi_processor_register_performance(struct acpi_processor_performance
*performance, unsigned int cpu) *performance, unsigned int cpu)
{ {
struct acpi_processor *pr; struct acpi_processor *pr;
if (!(acpi_processor_ppc_status & PPC_REGISTERED)) if (!(acpi_processor_ppc_status & PPC_REGISTERED))
return -EINVAL; return -EINVAL;
...@@ -781,8 +681,6 @@ acpi_processor_register_performance(struct acpi_processor_performance ...@@ -781,8 +681,6 @@ acpi_processor_register_performance(struct acpi_processor_performance
return -EIO; return -EIO;
} }
acpi_cpufreq_add_file(pr);
mutex_unlock(&performance_mutex); mutex_unlock(&performance_mutex);
return 0; return 0;
} }
...@@ -795,7 +693,6 @@ acpi_processor_unregister_performance(struct acpi_processor_performance ...@@ -795,7 +693,6 @@ acpi_processor_unregister_performance(struct acpi_processor_performance
{ {
struct acpi_processor *pr; struct acpi_processor *pr;
mutex_lock(&performance_mutex); mutex_lock(&performance_mutex);
pr = per_cpu(processors, cpu); pr = per_cpu(processors, cpu);
...@@ -808,8 +705,6 @@ acpi_processor_unregister_performance(struct acpi_processor_performance ...@@ -808,8 +705,6 @@ acpi_processor_unregister_performance(struct acpi_processor_performance
kfree(pr->performance->states); kfree(pr->performance->states);
pr->performance = NULL; pr->performance = NULL;
acpi_cpufreq_remove_file(pr);
mutex_unlock(&performance_mutex); mutex_unlock(&performance_mutex);
return; return;
......
...@@ -90,31 +90,6 @@ void __init acpi_old_suspend_ordering(void) ...@@ -90,31 +90,6 @@ void __init acpi_old_suspend_ordering(void)
old_suspend_ordering = true; old_suspend_ordering = true;
} }
/*
* 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;
/*
* The ACPI specification wants us to save NVS memory regions during hibernation
* and to restore them during the subsequent resume. However, it is not certain
* if this mechanism is going to work on all machines, so we allow the user to
* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
* option.
*/
static bool s4_no_nvs;
void __init acpi_s4_no_nvs(void)
{
s4_no_nvs = true;
}
/** /**
* acpi_pm_disable_gpes - Disable the GPEs. * acpi_pm_disable_gpes - Disable the GPEs.
*/ */
...@@ -193,6 +168,18 @@ static void acpi_pm_end(void) ...@@ -193,6 +168,18 @@ static void acpi_pm_end(void)
#endif /* CONFIG_ACPI_SLEEP */ #endif /* CONFIG_ACPI_SLEEP */
#ifdef CONFIG_SUSPEND #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); extern void do_suspend_lowlevel(void);
static u32 acpi_suspend_states[] = { static u32 acpi_suspend_states[] = {
...@@ -396,6 +383,20 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { ...@@ -396,6 +383,20 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
#endif /* CONFIG_SUSPEND */ #endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION #ifdef CONFIG_HIBERNATION
/*
* The ACPI specification wants us to save NVS memory regions during hibernation
* and to restore them during the subsequent resume. However, it is not certain
* if this mechanism is going to work on all machines, so we allow the user to
* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
* option.
*/
static bool s4_no_nvs;
void __init acpi_s4_no_nvs(void)
{
s4_no_nvs = true;
}
static unsigned long s4_hardware_signature; static unsigned long s4_hardware_signature;
static struct acpi_table_facs *facs; static struct acpi_table_facs *facs;
static bool nosigcheck; static bool nosigcheck;
...@@ -679,7 +680,7 @@ static void acpi_power_off_prepare(void) ...@@ -679,7 +680,7 @@ static void acpi_power_off_prepare(void)
static void acpi_power_off(void) static void acpi_power_off(void)
{ {
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
printk("%s called\n", __func__); printk(KERN_DEBUG "%s called\n", __func__);
local_irq_disable(); local_irq_disable();
acpi_enable_wakeup_device(ACPI_STATE_S5); acpi_enable_wakeup_device(ACPI_STATE_S5);
acpi_enter_sleep_state(ACPI_STATE_S5); acpi_enter_sleep_state(ACPI_STATE_S5);
......
...@@ -293,7 +293,12 @@ static void __init check_multiple_madt(void) ...@@ -293,7 +293,12 @@ static void __init check_multiple_madt(void)
int __init acpi_table_init(void) int __init acpi_table_init(void)
{ {
acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); acpi_status status;
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
if (ACPI_FAILURE(status))
return 1;
check_multiple_madt(); check_multiple_madt();
return 0; return 0;
} }
......
...@@ -1020,7 +1020,7 @@ acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset) ...@@ -1020,7 +1020,7 @@ acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
} }
seq_printf(seq, "levels: "); seq_printf(seq, "levels: ");
for (i = 0; i < dev->brightness->count; i++) for (i = 2; i < dev->brightness->count; i++)
seq_printf(seq, " %d", dev->brightness->levels[i]); seq_printf(seq, " %d", dev->brightness->levels[i]);
seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr); seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
...@@ -1059,7 +1059,7 @@ acpi_video_device_write_brightness(struct file *file, ...@@ -1059,7 +1059,7 @@ acpi_video_device_write_brightness(struct file *file,
return -EFAULT; return -EFAULT;
/* validate through the list of available levels */ /* validate through the list of available levels */
for (i = 0; i < dev->brightness->count; i++) for (i = 2; i < dev->brightness->count; i++)
if (level == dev->brightness->levels[i]) { if (level == dev->brightness->levels[i]) {
if (ACPI_SUCCESS if (ACPI_SUCCESS
(acpi_video_device_lcd_set_level(dev, level))) (acpi_video_device_lcd_set_level(dev, level)))
...@@ -1260,7 +1260,7 @@ static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset) ...@@ -1260,7 +1260,7 @@ static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
printk(KERN_WARNING PREFIX printk(KERN_WARNING PREFIX
"This indicates a BIOS bug. Please contact the manufacturer.\n"); "This indicates a BIOS bug. Please contact the manufacturer.\n");
} }
printk("%llx\n", options); printk(KERN_WARNING "%llx\n", options);
seq_printf(seq, "can POST: <integrated video>"); seq_printf(seq, "can POST: <integrated video>");
if (options & 2) if (options & 2)
seq_printf(seq, " <PCI video>"); seq_printf(seq, " <PCI video>");
...@@ -1712,7 +1712,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, ...@@ -1712,7 +1712,7 @@ acpi_video_get_next_level(struct acpi_video_device *device,
max = max_below = 0; max = max_below = 0;
min = min_above = 255; min = min_above = 255;
/* Find closest level to level_current */ /* Find closest level to level_current */
for (i = 0; i < device->brightness->count; i++) { for (i = 2; i < device->brightness->count; i++) {
l = device->brightness->levels[i]; l = device->brightness->levels[i];
if (abs(l - level_current) < abs(delta)) { if (abs(l - level_current) < abs(delta)) {
delta = l - level_current; delta = l - level_current;
...@@ -1722,7 +1722,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, ...@@ -1722,7 +1722,7 @@ acpi_video_get_next_level(struct acpi_video_device *device,
} }
/* Ajust level_current to closest available level */ /* Ajust level_current to closest available level */
level_current += delta; level_current += delta;
for (i = 0; i < device->brightness->count; i++) { for (i = 2; i < device->brightness->count; i++) {
l = device->brightness->levels[i]; l = device->brightness->levels[i];
if (l < min) if (l < min)
min = l; min = l;
...@@ -2006,6 +2006,12 @@ static int acpi_video_bus_add(struct acpi_device *device) ...@@ -2006,6 +2006,12 @@ static int acpi_video_bus_add(struct acpi_device *device)
device->pnp.bus_id[3] = '0' + instance; device->pnp.bus_id[3] = '0' + instance;
instance ++; instance ++;
} }
/* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
if (!strcmp(device->pnp.bus_id, "VGA")) {
if (instance)
device->pnp.bus_id[3] = '0' + instance;
instance++;
}
video->device = device; video->device = device;
strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
......
...@@ -42,6 +42,7 @@ config ASUS_LAPTOP ...@@ -42,6 +42,7 @@ config ASUS_LAPTOP
depends on LEDS_CLASS depends on LEDS_CLASS
depends on NEW_LEDS depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_CLASS_DEVICE
depends on INPUT
---help--- ---help---
This is the new Linux driver for Asus laptops. It may also support some This is the new Linux driver for Asus laptops. It may also support some
MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/input.h>
#define ASUS_LAPTOP_VERSION "0.42" #define ASUS_LAPTOP_VERSION "0.42"
...@@ -181,6 +182,8 @@ struct asus_hotk { ...@@ -181,6 +182,8 @@ struct asus_hotk {
u8 light_level; //light sensor level u8 light_level; //light sensor level
u8 light_switch; //light sensor switch value u8 light_switch; //light sensor switch value
u16 event_count[128]; //count for each event TODO make this better u16 event_count[128]; //count for each event TODO make this better
struct input_dev *inputdev;
u16 *keycode_map;
}; };
/* /*
...@@ -250,6 +253,37 @@ ASUS_LED(rled, "record"); ...@@ -250,6 +253,37 @@ ASUS_LED(rled, "record");
ASUS_LED(pled, "phone"); ASUS_LED(pled, "phone");
ASUS_LED(gled, "gaming"); ASUS_LED(gled, "gaming");
struct key_entry {
char type;
u8 code;
u16 keycode;
};
enum { KE_KEY, KE_END };
static struct key_entry asus_keymap[] = {
{KE_KEY, 0x30, KEY_VOLUMEUP},
{KE_KEY, 0x31, KEY_VOLUMEDOWN},
{KE_KEY, 0x32, KEY_MUTE},
{KE_KEY, 0x33, KEY_SWITCHVIDEOMODE},
{KE_KEY, 0x34, KEY_SWITCHVIDEOMODE},
{KE_KEY, 0x40, KEY_PREVIOUSSONG},
{KE_KEY, 0x41, KEY_NEXTSONG},
{KE_KEY, 0x43, KEY_STOP},
{KE_KEY, 0x45, KEY_PLAYPAUSE},
{KE_KEY, 0x50, KEY_EMAIL},
{KE_KEY, 0x51, KEY_WWW},
{KE_KEY, 0x5C, BTN_EXTRA}, /* Performance */
{KE_KEY, 0x5D, KEY_WLAN},
{KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
{KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
{KE_KEY, 0x82, KEY_CAMERA},
{KE_KEY, 0x8A, KEY_TV},
{KE_KEY, 0x95, KEY_MEDIA},
{KE_KEY, 0x99, KEY_PHONE},
{KE_END, 0},
};
/* /*
* This function evaluates an ACPI method, given an int as parameter, the * This function evaluates an ACPI method, given an int as parameter, the
* method is searched within the scope of the handle, can be NULL. The output * method is searched within the scope of the handle, can be NULL. The output
...@@ -720,8 +754,68 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr, ...@@ -720,8 +754,68 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
return store_status(buf, count, NULL, GPS_ON); return store_status(buf, count, NULL, GPS_ON);
} }
/*
* Hotkey functions
*/
static struct key_entry *asus_get_entry_by_scancode(int code)
{
struct key_entry *key;
for (key = asus_keymap; key->type != KE_END; key++)
if (code == key->code)
return key;
return NULL;
}
static struct key_entry *asus_get_entry_by_keycode(int code)
{
struct key_entry *key;
for (key = asus_keymap; key->type != KE_END; key++)
if (code == key->keycode && key->type == KE_KEY)
return key;
return NULL;
}
static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
{
struct key_entry *key = asus_get_entry_by_scancode(scancode);
if (key && key->type == KE_KEY) {
*keycode = key->keycode;
return 0;
}
return -EINVAL;
}
static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
{
struct key_entry *key;
int old_keycode;
if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;
key = asus_get_entry_by_scancode(scancode);
if (key && key->type == KE_KEY) {
old_keycode = key->keycode;
key->keycode = keycode;
set_bit(keycode, dev->keybit);
if (!asus_get_entry_by_keycode(old_keycode))
clear_bit(old_keycode, dev->keybit);
return 0;
}
return -EINVAL;
}
static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
{ {
static struct key_entry *key;
/* TODO Find a better way to handle events count. */ /* TODO Find a better way to handle events count. */
if (!hotk) if (!hotk)
return; return;
...@@ -738,10 +832,24 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) ...@@ -738,10 +832,24 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
lcd_blank(FB_BLANK_POWERDOWN); lcd_blank(FB_BLANK_POWERDOWN);
} }
acpi_bus_generate_proc_event(hotk->device, event, acpi_bus_generate_netlink_event(hotk->device->pnp.device_class,
dev_name(&hotk->device->dev), event,
hotk->event_count[event % 128]++); hotk->event_count[event % 128]++);
return; if (hotk->inputdev) {
key = asus_get_entry_by_scancode(event);
if (!key)
return ;
switch (key->type) {
case KE_KEY:
input_report_key(hotk->inputdev, key->keycode, 1);
input_sync(hotk->inputdev);
input_report_key(hotk->inputdev, key->keycode, 0);
input_sync(hotk->inputdev);
break;
}
}
} }
#define ASUS_CREATE_DEVICE_ATTR(_name) \ #define ASUS_CREATE_DEVICE_ATTR(_name) \
...@@ -959,6 +1067,38 @@ static int asus_hotk_get_info(void) ...@@ -959,6 +1067,38 @@ static int asus_hotk_get_info(void)
return AE_OK; return AE_OK;
} }
static int asus_input_init(void)
{
const struct key_entry *key;
int result;
hotk->inputdev = input_allocate_device();
if (!hotk->inputdev) {
printk(ASUS_INFO "Unable to allocate input device\n");
return 0;
}
hotk->inputdev->name = "Asus Laptop extra buttons";
hotk->inputdev->phys = ASUS_HOTK_FILE "/input0";
hotk->inputdev->id.bustype = BUS_HOST;
hotk->inputdev->getkeycode = asus_getkeycode;
hotk->inputdev->setkeycode = asus_setkeycode;
for (key = asus_keymap; key->type != KE_END; key++) {
switch (key->type) {
case KE_KEY:
set_bit(EV_KEY, hotk->inputdev->evbit);
set_bit(key->keycode, hotk->inputdev->keybit);
break;
}
}
result = input_register_device(hotk->inputdev);
if (result) {
printk(ASUS_INFO "Unable to register input device\n");
input_free_device(hotk->inputdev);
}
return result;
}
static int asus_hotk_check(void) static int asus_hotk_check(void)
{ {
int result = 0; int result = 0;
...@@ -1044,7 +1184,7 @@ static int asus_hotk_add(struct acpi_device *device) ...@@ -1044,7 +1184,7 @@ static int asus_hotk_add(struct acpi_device *device)
/* GPS is on by default */ /* GPS is on by default */
write_status(NULL, 1, GPS_ON); write_status(NULL, 1, GPS_ON);
end: end:
if (result) { if (result) {
kfree(hotk->name); kfree(hotk->name);
kfree(hotk); kfree(hotk);
...@@ -1091,10 +1231,17 @@ static void asus_led_exit(void) ...@@ -1091,10 +1231,17 @@ static void asus_led_exit(void)
ASUS_LED_UNREGISTER(gled); ASUS_LED_UNREGISTER(gled);
} }
static void asus_input_exit(void)
{
if (hotk->inputdev)
input_unregister_device(hotk->inputdev);
}
static void __exit asus_laptop_exit(void) static void __exit asus_laptop_exit(void)
{ {
asus_backlight_exit(); asus_backlight_exit();
asus_led_exit(); asus_led_exit();
asus_input_exit();
acpi_bus_unregister_driver(&asus_hotk_driver); acpi_bus_unregister_driver(&asus_hotk_driver);
sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
...@@ -1216,6 +1363,10 @@ static int __init asus_laptop_init(void) ...@@ -1216,6 +1363,10 @@ static int __init asus_laptop_init(void)
printk(ASUS_INFO "Brightness ignored, must be controlled by " printk(ASUS_INFO "Brightness ignored, must be controlled by "
"ACPI video driver\n"); "ACPI video driver\n");
result = asus_input_init();
if (result)
goto fail_input;
result = asus_led_init(dev); result = asus_led_init(dev);
if (result) if (result)
goto fail_led; goto fail_led;
...@@ -1242,22 +1393,25 @@ static int __init asus_laptop_init(void) ...@@ -1242,22 +1393,25 @@ static int __init asus_laptop_init(void)
return 0; return 0;
fail_sysfs: fail_sysfs:
platform_device_del(asuspf_device); platform_device_del(asuspf_device);
fail_platform_device2: fail_platform_device2:
platform_device_put(asuspf_device); platform_device_put(asuspf_device);
fail_platform_device1: fail_platform_device1:
platform_driver_unregister(&asuspf_driver); platform_driver_unregister(&asuspf_driver);
fail_platform_driver: fail_platform_driver:
asus_led_exit(); asus_led_exit();
fail_led: fail_led:
asus_input_exit();
fail_input:
asus_backlight_exit(); asus_backlight_exit();
fail_backlight: fail_backlight:
return result; return result;
} }
......
...@@ -143,6 +143,7 @@ struct asus_hotk { ...@@ -143,6 +143,7 @@ struct asus_hotk {
S1300N, S5200N*/ S1300N, S5200N*/
A4S, /* Z81sp */ A4S, /* Z81sp */
F3Sa, /* (Centrino) */ F3Sa, /* (Centrino) */
R1F,
END_MODEL END_MODEL
} model; /* Models currently supported */ } model; /* Models currently supported */
u16 event_count[128]; /* Count for each event TODO make this better */ u16 event_count[128]; /* Count for each event TODO make this better */
...@@ -420,7 +421,18 @@ static struct model_data model_conf[END_MODEL] = { ...@@ -420,7 +421,18 @@ static struct model_data model_conf[END_MODEL] = {
.display_get = "\\ADVG", .display_get = "\\ADVG",
.display_set = "SDSP", .display_set = "SDSP",
}, },
{
.name = "R1F",
.mt_bt_switch = "BLED",
.mt_mled = "MLED",
.mt_wled = "WLED",
.mt_lcd_switch = "\\Q10",
.lcd_status = "\\GP06",
.brightness_set = "SPLV",
.brightness_get = "GPLV",
.display_set = "SDSP",
.display_get = "\\INFB"
}
}; };
/* procdir we use */ /* procdir we use */
...@@ -1165,6 +1177,8 @@ static int asus_model_match(char *model) ...@@ -1165,6 +1177,8 @@ static int asus_model_match(char *model)
return W3V; return W3V;
else if (strncmp(model, "W5A", 3) == 0) else if (strncmp(model, "W5A", 3) == 0)
return W5A; return W5A;
else if (strncmp(model, "R1F", 3) == 0)
return R1F;
else if (strncmp(model, "A4S", 3) == 0) else if (strncmp(model, "A4S", 3) == 0)
return A4S; return A4S;
else if (strncmp(model, "F3Sa", 4) == 0) else if (strncmp(model, "F3Sa", 4) == 0)
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/rfkill.h> #include <linux/rfkill.h>
#include <linux/pci.h>
#define EEEPC_LAPTOP_VERSION "0.1" #define EEEPC_LAPTOP_VERSION "0.1"
...@@ -161,6 +162,10 @@ static struct key_entry eeepc_keymap[] = { ...@@ -161,6 +162,10 @@ static struct key_entry eeepc_keymap[] = {
{KE_KEY, 0x13, KEY_MUTE }, {KE_KEY, 0x13, KEY_MUTE },
{KE_KEY, 0x14, KEY_VOLUMEDOWN }, {KE_KEY, 0x14, KEY_VOLUMEDOWN },
{KE_KEY, 0x15, KEY_VOLUMEUP }, {KE_KEY, 0x15, KEY_VOLUMEUP },
{KE_KEY, 0x1a, KEY_COFFEE },
{KE_KEY, 0x1b, KEY_ZOOM },
{KE_KEY, 0x1c, KEY_PROG2 },
{KE_KEY, 0x1d, KEY_PROG3 },
{KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
{KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
{KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
...@@ -510,9 +515,45 @@ static int eeepc_hotk_check(void) ...@@ -510,9 +515,45 @@ static int eeepc_hotk_check(void)
static void notify_brn(void) static void notify_brn(void)
{ {
struct backlight_device *bd = eeepc_backlight_device; struct backlight_device *bd = eeepc_backlight_device;
if (bd)
bd->props.brightness = read_brightness(bd); bd->props.brightness = read_brightness(bd);
} }
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
{
struct pci_dev *dev;
struct pci_bus *bus = pci_find_bus(0, 1);
if (event != ACPI_NOTIFY_BUS_CHECK)
return;
if (!bus) {
printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
return;
}
if (get_acpi(CM_ASL_WLAN) == 1) {
dev = pci_get_slot(bus, 0);
if (dev) {
/* Device already present */
pci_dev_put(dev);
return;
}
dev = pci_scan_single_device(bus, 0);
if (dev) {
pci_bus_assign_resources(bus);
if (pci_bus_add_device(dev))
printk(EEEPC_ERR "Unable to hotplug wifi\n");
}
} else {
dev = pci_get_slot(bus, 0);
if (dev) {
pci_remove_bus_device(dev);
pci_dev_put(dev);
}
}
}
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
{ {
static struct key_entry *key; static struct key_entry *key;
...@@ -520,7 +561,8 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) ...@@ -520,7 +561,8 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
return; return;
if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
notify_brn(); notify_brn();
acpi_bus_generate_proc_event(ehotk->device, event, acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
dev_name(&ehotk->device->dev), event,
ehotk->event_count[event % 128]++); ehotk->event_count[event % 128]++);
if (ehotk->inputdev) { if (ehotk->inputdev) {
key = eepc_get_entry_by_scancode(event); key = eepc_get_entry_by_scancode(event);
...@@ -539,6 +581,45 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) ...@@ -539,6 +581,45 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
} }
} }
static int eeepc_register_rfkill_notifier(char *node)
{
acpi_status status = AE_OK;
acpi_handle handle;
status = acpi_get_handle(NULL, node, &handle);
if (ACPI_SUCCESS(status)) {
status = acpi_install_notify_handler(handle,
ACPI_SYSTEM_NOTIFY,
eeepc_rfkill_notify,
NULL);
if (ACPI_FAILURE(status))
printk(EEEPC_WARNING
"Failed to register notify on %s\n", node);
} else
return -ENODEV;
return 0;
}
static void eeepc_unregister_rfkill_notifier(char *node)
{
acpi_status status = AE_OK;
acpi_handle handle;
status = acpi_get_handle(NULL, node, &handle);
if (ACPI_SUCCESS(status)) {
status = acpi_remove_notify_handler(handle,
ACPI_SYSTEM_NOTIFY,
eeepc_rfkill_notify);
if (ACPI_FAILURE(status))
printk(EEEPC_ERR
"Error removing rfkill notify handler %s\n",
node);
}
}
static int eeepc_hotk_add(struct acpi_device *device) static int eeepc_hotk_add(struct acpi_device *device)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
...@@ -558,7 +639,7 @@ static int eeepc_hotk_add(struct acpi_device *device) ...@@ -558,7 +639,7 @@ static int eeepc_hotk_add(struct acpi_device *device)
ehotk->device = device; ehotk->device = device;
result = eeepc_hotk_check(); result = eeepc_hotk_check();
if (result) if (result)
goto end; goto ehotk_fail;
status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
eeepc_hotk_notify, ehotk); eeepc_hotk_notify, ehotk);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
...@@ -569,18 +650,25 @@ static int eeepc_hotk_add(struct acpi_device *device) ...@@ -569,18 +650,25 @@ static int eeepc_hotk_add(struct acpi_device *device)
RFKILL_TYPE_WLAN); RFKILL_TYPE_WLAN);
if (!ehotk->eeepc_wlan_rfkill) if (!ehotk->eeepc_wlan_rfkill)
goto end; goto wlan_fail;
ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
if (get_acpi(CM_ASL_WLAN) == 1) if (get_acpi(CM_ASL_WLAN) == 1) {
ehotk->eeepc_wlan_rfkill->state = ehotk->eeepc_wlan_rfkill->state =
RFKILL_STATE_UNBLOCKED; RFKILL_STATE_UNBLOCKED;
else rfkill_set_default(RFKILL_TYPE_WLAN,
RFKILL_STATE_UNBLOCKED);
} else {
ehotk->eeepc_wlan_rfkill->state = ehotk->eeepc_wlan_rfkill->state =
RFKILL_STATE_SOFT_BLOCKED; RFKILL_STATE_SOFT_BLOCKED;
rfkill_register(ehotk->eeepc_wlan_rfkill); rfkill_set_default(RFKILL_TYPE_WLAN,
RFKILL_STATE_SOFT_BLOCKED);
}
result = rfkill_register(ehotk->eeepc_wlan_rfkill);
if (result)
goto wlan_fail;
} }
if (get_acpi(CM_ASL_BLUETOOTH) != -1) { if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
...@@ -588,27 +676,47 @@ static int eeepc_hotk_add(struct acpi_device *device) ...@@ -588,27 +676,47 @@ static int eeepc_hotk_add(struct acpi_device *device)
rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
if (!ehotk->eeepc_bluetooth_rfkill) if (!ehotk->eeepc_bluetooth_rfkill)
goto end; goto bluetooth_fail;
ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
ehotk->eeepc_bluetooth_rfkill->toggle_radio = ehotk->eeepc_bluetooth_rfkill->toggle_radio =
eeepc_bluetooth_rfkill_set; eeepc_bluetooth_rfkill_set;
ehotk->eeepc_bluetooth_rfkill->get_state = ehotk->eeepc_bluetooth_rfkill->get_state =
eeepc_bluetooth_rfkill_state; eeepc_bluetooth_rfkill_state;
if (get_acpi(CM_ASL_BLUETOOTH) == 1) if (get_acpi(CM_ASL_BLUETOOTH) == 1) {
ehotk->eeepc_bluetooth_rfkill->state = ehotk->eeepc_bluetooth_rfkill->state =
RFKILL_STATE_UNBLOCKED; RFKILL_STATE_UNBLOCKED;
else rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
RFKILL_STATE_UNBLOCKED);
} else {
ehotk->eeepc_bluetooth_rfkill->state = ehotk->eeepc_bluetooth_rfkill->state =
RFKILL_STATE_SOFT_BLOCKED; RFKILL_STATE_SOFT_BLOCKED;
rfkill_register(ehotk->eeepc_bluetooth_rfkill); rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
RFKILL_STATE_SOFT_BLOCKED);
} }
end: result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
if (result) { if (result)
goto bluetooth_fail;
}
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
return 0;
bluetooth_fail:
if (ehotk->eeepc_bluetooth_rfkill)
rfkill_free(ehotk->eeepc_bluetooth_rfkill);
rfkill_unregister(ehotk->eeepc_wlan_rfkill);
ehotk->eeepc_wlan_rfkill = NULL;
wlan_fail:
if (ehotk->eeepc_wlan_rfkill)
rfkill_free(ehotk->eeepc_wlan_rfkill);
ehotk_fail:
kfree(ehotk); kfree(ehotk);
ehotk = NULL; ehotk = NULL;
}
return result; return result;
} }
...@@ -622,6 +730,10 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type) ...@@ -622,6 +730,10 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
eeepc_hotk_notify); eeepc_hotk_notify);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
printk(EEEPC_ERR "Error removing notify handler\n"); printk(EEEPC_ERR "Error removing notify handler\n");
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
kfree(ehotk); kfree(ehotk);
return 0; return 0;
} }
...@@ -737,13 +849,21 @@ static void eeepc_backlight_exit(void) ...@@ -737,13 +849,21 @@ static void eeepc_backlight_exit(void)
{ {
if (eeepc_backlight_device) if (eeepc_backlight_device)
backlight_device_unregister(eeepc_backlight_device); backlight_device_unregister(eeepc_backlight_device);
if (ehotk->inputdev) eeepc_backlight_device = NULL;
input_unregister_device(ehotk->inputdev); }
static void eeepc_rfkill_exit(void)
{
if (ehotk->eeepc_wlan_rfkill) if (ehotk->eeepc_wlan_rfkill)
rfkill_unregister(ehotk->eeepc_wlan_rfkill); rfkill_unregister(ehotk->eeepc_wlan_rfkill);
if (ehotk->eeepc_bluetooth_rfkill) if (ehotk->eeepc_bluetooth_rfkill)
rfkill_unregister(ehotk->eeepc_bluetooth_rfkill); rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
eeepc_backlight_device = NULL; }
static void eeepc_input_exit(void)
{
if (ehotk->inputdev)
input_unregister_device(ehotk->inputdev);
} }
static void eeepc_hwmon_exit(void) static void eeepc_hwmon_exit(void)
...@@ -762,6 +882,8 @@ static void eeepc_hwmon_exit(void) ...@@ -762,6 +882,8 @@ static void eeepc_hwmon_exit(void)
static void __exit eeepc_laptop_exit(void) static void __exit eeepc_laptop_exit(void)
{ {
eeepc_backlight_exit(); eeepc_backlight_exit();
eeepc_rfkill_exit();
eeepc_input_exit();
eeepc_hwmon_exit(); eeepc_hwmon_exit();
acpi_bus_unregister_driver(&eeepc_hotk_driver); acpi_bus_unregister_driver(&eeepc_hotk_driver);
sysfs_remove_group(&platform_device->dev.kobj, sysfs_remove_group(&platform_device->dev.kobj,
...@@ -865,6 +987,8 @@ static int __init eeepc_laptop_init(void) ...@@ -865,6 +987,8 @@ static int __init eeepc_laptop_init(void)
fail_hwmon: fail_hwmon:
eeepc_backlight_exit(); eeepc_backlight_exit();
fail_backlight: fail_backlight:
eeepc_input_exit();
eeepc_rfkill_exit();
return result; return result;
} }
......
...@@ -507,7 +507,7 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) ...@@ -507,7 +507,7 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
hkey_num = result & 0xf; hkey_num = result & 0xf;
if (hkey_num < 0 || hkey_num > ARRAY_SIZE(pcc->keymap)) { if (hkey_num < 0 || hkey_num >= ARRAY_SIZE(pcc->keymap)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"hotkey number out of range: %d\n", "hotkey number out of range: %d\n",
hkey_num)); hkey_num));
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define ACPI_PDC_SMP_T_SWCOORD (0x0080) #define ACPI_PDC_SMP_T_SWCOORD (0x0080)
#define ACPI_PDC_C_C1_FFH (0x0100) #define ACPI_PDC_C_C1_FFH (0x0100)
#define ACPI_PDC_C_C2C3_FFH (0x0200) #define ACPI_PDC_C_C2C3_FFH (0x0200)
#define ACPI_PDC_SMP_P_HWCOORD (0x0800)
#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \ #define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \ ACPI_PDC_C_C1_HALT | \
...@@ -22,6 +23,7 @@ ...@@ -22,6 +23,7 @@
#define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \ #define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \ ACPI_PDC_C_C1_HALT | \
ACPI_PDC_SMP_P_SWCOORD | \ ACPI_PDC_SMP_P_SWCOORD | \
ACPI_PDC_SMP_P_HWCOORD | \
ACPI_PDC_P_FFH) ACPI_PDC_P_FFH)
#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ #define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
......
...@@ -57,16 +57,6 @@ int pm_notifier_call_chain(unsigned long val) ...@@ -57,16 +57,6 @@ int pm_notifier_call_chain(unsigned long val)
#ifdef CONFIG_PM_DEBUG #ifdef CONFIG_PM_DEBUG
int pm_test_level = TEST_NONE; int pm_test_level = TEST_NONE;
static int suspend_test(int level)
{
if (pm_test_level == level) {
printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
mdelay(5000);
return 1;
}
return 0;
}
static const char * const pm_tests[__TEST_AFTER_LAST] = { static const char * const pm_tests[__TEST_AFTER_LAST] = {
[TEST_NONE] = "none", [TEST_NONE] = "none",
[TEST_CORE] = "core", [TEST_CORE] = "core",
...@@ -125,14 +115,24 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, ...@@ -125,14 +115,24 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
} }
power_attr(pm_test); power_attr(pm_test);
#else /* !CONFIG_PM_DEBUG */ #endif /* CONFIG_PM_DEBUG */
static inline int suspend_test(int level) { return 0; }
#endif /* !CONFIG_PM_DEBUG */
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
static int suspend_test(int level)
{
#ifdef CONFIG_PM_DEBUG
if (pm_test_level == level) {
printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
mdelay(5000);
return 1;
}
#endif /* !CONFIG_PM_DEBUG */
return 0;
}
#ifdef CONFIG_PM_TEST_SUSPEND #ifdef CONFIG_PM_TEST_SUSPEND
/* /*
......
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