#include <linux/list.h>
#include <linux/sched.h>
#include <linux/pm.h>
-#include <linux/pm_legacy.h>
#include <linux/device.h>
#include <linux/proc_fs.h>
+#include <linux/acpi.h>
#ifdef CONFIG_X86
#include <asm/mpspec.h>
#endif
+#include <linux/pci.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_BUS_COMPONENT
-ACPI_MODULE_NAME("acpi_bus")
-#ifdef CONFIG_X86
-extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
-#endif
-
-struct fadt_descriptor acpi_fadt;
-EXPORT_SYMBOL(acpi_fadt);
+ACPI_MODULE_NAME("bus");
struct acpi_device *acpi_root;
struct proc_dir_entry *acpi_root_dir;
#define STRUCT_TO_INT(s) (*((int*)&s))
+static int set_power_nocheck(const struct dmi_system_id *id)
+{
+ printk(KERN_NOTICE PREFIX "%s detected - "
+ "disable power check in power transistion\n", id->ident);
+ acpi_power_nocheck = 1;
+ return 0;
+}
+static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
+ {
+ set_power_nocheck, "HP Pavilion 05", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
+ {},
+};
+
+
/* --------------------------------------------------------------------------
Device Management
-------------------------------------------------------------------------- */
int acpi_bus_get_status(struct acpi_device *device)
{
acpi_status status = AE_OK;
- unsigned long sta = 0;
+ unsigned long long sta = 0;
if (!device)
}
/*
- * Otherwise we assume the status of our parent (unless we don't
- * have one, in which case status is implied).
+ * According to ACPI spec some device can be present and functional
+ * even if the parent is not present but functional.
+ * In such conditions the child device should not inherit the status
+ * from the parent.
*/
- else if (device->parent)
- device->status = device->parent->status;
else
- STRUCT_TO_INT(device->status) = 0x0F;
+ STRUCT_TO_INT(device->status) =
+ ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
if (device->status.functional && !device->status.present) {
- printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
- "functional but not present; setting present\n",
- device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status));
- device->status.present = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
+ "functional but not present;\n",
+ device->pnp.bus_id,
+ (u32) STRUCT_TO_INT(device->status)));
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
EXPORT_SYMBOL(acpi_bus_get_status);
+void acpi_bus_private_data_handler(acpi_handle handle,
+ u32 function, void *context)
+{
+ return;
+}
+EXPORT_SYMBOL(acpi_bus_private_data_handler);
+
+int acpi_bus_get_private_data(acpi_handle handle, void **data)
+{
+ acpi_status status = AE_OK;
+
+ if (!*data)
+ return -EINVAL;
+
+ status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
+ if (ACPI_FAILURE(status) || !*data) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
+ handle));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(acpi_bus_get_private_data);
+
/* --------------------------------------------------------------------------
Power Management
-------------------------------------------------------------------------- */
int result = 0;
acpi_status status = 0;
struct acpi_device *device = NULL;
- unsigned long psc = 0;
+ unsigned long long psc = 0;
result = acpi_bus_get_device(handle, &device);
*state = ACPI_STATE_D0;
} else {
/*
- * Get the device's power state either directly (via _PSC) or
+ * Get the device's power state either directly (via _PSC) or
* indirectly (via power resources).
*/
if (device->power.flags.explicit_get) {
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- device->dev.kobj.name));
+ kobject_name(&device->dev.kobj)));
return -ENODEV;
}
/*
- * Get device's current power state if it's unknown
- * This means device power state isn't initialized or previous setting failed
+ * Get device's current power state
*/
- if (!device->flags.force_power_state) {
- if (device->power.state == ACPI_STATE_UNKNOWN)
- acpi_bus_get_power(device->handle, &device->power.state);
- if (state == device->power.state) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
- state));
- return 0;
- }
+ if (!acpi_power_nocheck) {
+ /*
+ * Maybe the incorrect power state is returned on the bogus
+ * bios, which is different with the real power state.
+ * For example: the bios returns D0 state and the real power
+ * state is D3. OS expects to set the device to D0 state. In
+ * such case if OS uses the power state returned by the BIOS,
+ * the device can't be transisted to the correct power state.
+ * So if the acpi_power_nocheck is set, it is unnecessary to
+ * get the power state by calling acpi_bus_get_power.
+ */
+ acpi_bus_get_power(device->handle, &device->power.state);
}
+ if ((state == device->power.state) && !device->flags.force_power_state) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
+ state));
+ return 0;
+ }
+
if (!device->power.states[state].flags.valid) {
printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
return -ENODEV;
printk(KERN_WARNING PREFIX
"Transitioning device [%s] to D%d\n",
device->pnp.bus_id, state);
- else
+ else {
+ device->power.state = state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to D%d\n",
device->pnp.bus_id, state));
+ }
return result;
}
EXPORT_SYMBOL(acpi_bus_set_power);
+bool acpi_bus_power_manageable(acpi_handle handle)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ return result ? false : device->flags.power_manageable;
+}
+
+EXPORT_SYMBOL(acpi_bus_power_manageable);
+
+bool acpi_bus_can_wakeup(acpi_handle handle)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ return result ? false : device->wakeup.flags.valid;
+}
+
+EXPORT_SYMBOL(acpi_bus_can_wakeup);
+
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROC_EVENT
static DEFINE_SPINLOCK(acpi_bus_event_lock);
LIST_HEAD(acpi_bus_event_list);
extern int event_is_open;
-int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
+int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
{
- struct acpi_bus_event *event = NULL;
+ struct acpi_bus_event *event;
unsigned long flags = 0;
-
- if (!device)
- return -EINVAL;
-
/* drop event on the floor if no one's listening */
if (!event_is_open)
return 0;
if (!event)
return -ENOMEM;
- strcpy(event->device_class, device->pnp.device_class);
- strcpy(event->bus_id, device->pnp.bus_id);
+ strcpy(event->device_class, device_class);
+ strcpy(event->bus_id, bus_id);
event->type = type;
event->data = data;
wake_up_interruptible(&acpi_bus_event_queue);
return 0;
+
+}
+
+EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);
+
+int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
+{
+ if (!device)
+ return -EINVAL;
+ return acpi_bus_generate_proc_event4(device->pnp.device_class,
+ device->pnp.bus_id, type, data);
}
-EXPORT_SYMBOL(acpi_bus_generate_event);
+EXPORT_SYMBOL(acpi_bus_generate_proc_event);
int acpi_bus_receive_event(struct acpi_bus_event *event)
{
}
spin_lock_irqsave(&acpi_bus_event_lock, flags);
- entry =
- list_entry(acpi_bus_event_list.next, struct acpi_bus_event, node);
- if (entry)
+ if (!list_empty(&acpi_bus_event_list)) {
+ entry = list_entry(acpi_bus_event_list.next,
+ struct acpi_bus_event, node);
list_del(&entry->node);
+ }
spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
if (!entry)
return 0;
}
-EXPORT_SYMBOL(acpi_bus_receive_event);
+#endif /* CONFIG_ACPI_PROC_EVENT */
/* --------------------------------------------------------------------------
Notification Handling
return 0;
}
+static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
+int register_acpi_bus_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
+
+void unregister_acpi_bus_notifier(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
+
/**
* acpi_bus_notify
* ---------------
int result = 0;
struct acpi_device *device = NULL;
+ blocking_notifier_call_chain(&acpi_bus_notify_list,
+ type, (void *)handle);
if (acpi_bus_get_device(handle, &device))
return;
"Received BUS CHECK notification for device [%s]\n",
device->pnp.bus_id));
result = acpi_bus_check_scope(device);
- /*
+ /*
* TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c).
*/
"Received DEVICE CHECK notification for device [%s]\n",
device->pnp.bus_id));
result = acpi_bus_check_device(device, NULL);
- /*
+ /*
* TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c).
*/
char *message = NULL;
- /*
+ /*
* Let the system know what interrupt model we are using by
* evaluating the \_PIC object, if exists.
*/
case ACPI_IRQ_MODEL_IOSAPIC:
message = "IOSAPIC";
break;
+ case ACPI_IRQ_MODEL_PLATFORM:
+ message = "platform specific model";
+ break;
default:
printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
return -ENODEV;
return 0;
}
+u8 acpi_gbl_permanent_mmap;
+
+
void __init acpi_early_init(void)
{
acpi_status status = AE_OK;
- struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt };
-
if (acpi_disabled)
return;
if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE;
+ acpi_gbl_permanent_mmap = 1;
+
+ status = acpi_reallocate_root_table();
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX
+ "Unable to reallocate ACPI tables\n");
+ goto error0;
+ }
+
status = acpi_initialize_subsystem();
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX
goto error0;
}
- /*
- * Get a separate copy of the FADT for use by other drivers.
- */
- status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Unable to get the FADT\n");
- goto error0;
- }
#ifdef CONFIG_X86
if (!acpi_ioapic) {
- extern acpi_interrupt_flags acpi_sci_flags;
-
/* compatible (0) means level (3) */
- if (acpi_sci_flags.trigger == 0)
- acpi_sci_flags.trigger = 3;
-
+ if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) {
+ acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK;
+ acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL;
+ }
/* Set PIC-mode SCI trigger type */
- acpi_pic_sci_set_trigger(acpi_fadt.sci_int,
- acpi_sci_flags.trigger);
+ acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
+ (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
} else {
- extern int acpi_sci_override_gsi;
/*
- * now that acpi_fadt is initialized,
+ * now that acpi_gbl_FADT is initialized,
* update it with result from INT_SRC_OVR parsing
*/
- acpi_fadt.sci_int = acpi_sci_override_gsi;
+ acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
}
#endif
"Unable to initialize ACPI OS objects\n");
goto error1;
}
-#ifdef CONFIG_ACPI_EC
+
/*
* ACPI 2.0 requires the EC driver to be loaded and work before
* the EC device is found in the namespace (i.e. before acpi_initialize_objects()
* is called).
*
- * This is accomplished by looking for the ECDT table, and getting
+ * This is accomplished by looking for the ECDT table, and getting
* the EC parameters out of that.
*/
status = acpi_ec_ecdt_probe();
/* Ignore result. Not having an ECDT is not fatal. */
-#endif
status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
if (ACPI_FAILURE(status)) {
goto error1;
}
+ /*
+ * Maybe EC region is required at bus_scan/acpi_get_devices. So it
+ * is necessary to enable it as early as possible.
+ */
+ acpi_boot_ec_enable();
+
printk(KERN_INFO PREFIX "Interpreter enabled\n");
+ /* Initialize sleep structures */
+ acpi_sleep_init();
+
/*
* Get the system interrupt model and evaluate \_PIC.
*/
return -ENODEV;
}
-decl_subsys(acpi, NULL, NULL);
+struct kobject *acpi_kobj;
static int __init acpi_init(void)
{
return -ENODEV;
}
- result = firmware_register(&acpi_subsys);
- if (result < 0)
- printk(KERN_WARNING "%s: firmware_register error: %d\n",
- __FUNCTION__, result);
+ acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
+ if (!acpi_kobj) {
+ printk(KERN_WARNING "%s: kset create error\n", __func__);
+ acpi_kobj = NULL;
+ }
result = acpi_bus_init();
if (!result) {
-#ifdef CONFIG_PM_LEGACY
- if (!PM_IS_ACTIVE())
- pm_active = 1;
+ pci_mmcfg_late_init();
+ if (!(pm_flags & PM_APM))
+ pm_flags |= PM_ACPI;
else {
printk(KERN_INFO PREFIX
"APM is already active, exiting\n");
disable_acpi();
result = -ENODEV;
}
-#endif
} else
disable_acpi();
-
+ /*
+ * If the laptop falls into the DMI check table, the power state check
+ * will be disabled in the course of device power transistion.
+ */
+ dmi_check_system(power_nocheck_dmi_table);
return result;
}