From 74cad4ee9839669ad920257678ea0bf0a818cd3b Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Wed, 24 Jun 2009 11:49:49 +0800 Subject: ACPI: Make ACPI processor proc I/F depend on the ACPI_PROCFS Now whether the ACPI processor proc I/F is registered depends on the CONFIG_PROC. It had better depend on the CONFIG_ACPI_PROCFS. When the CONFIG_ACPI_PROCFS is unset in kernel configuration, the ACPI processor proc I/F won't be registered. Signed-off-by: Zhao Yakui Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 6 +++++- drivers/acpi/processor_core.c | 25 +++++++++++++++++++++---- drivers/acpi/processor_idle.c | 8 ++++++-- drivers/acpi/processor_thermal.c | 3 ++- drivers/acpi/processor_throttling.c | 3 ++- 5 files changed, 36 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 431f8b439553..f26db487752b 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -60,7 +60,11 @@ config ACPI_PROCFS /proc/acpi/fadt (/sys/firmware/acpi/tables/FACP) /proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer) /proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level) - + /proc/acpi/processor/*/power (/sys/devices/system/cpu/*/cpuidle/*) + /proc/acpi/processor/*/performance (/sys/devices/system/cpu/*/ + cpufreq/*) + /proc/acpi/processor/*/throttling (/sys/class/thermal/ + cooling_device*/*) This option has no effect on /proc/acpi/ files and functions which do not yet exist in /sys. diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 23f0fb84f1c1..1b166c1be167 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -81,7 +81,9 @@ MODULE_LICENSE("GPL"); static int acpi_processor_add(struct acpi_device *device); static int acpi_processor_start(struct acpi_device *device); static int acpi_processor_remove(struct acpi_device *device, int type); +#ifdef CONFIG_ACPI_PROCFS static int acpi_processor_info_open_fs(struct inode *inode, struct file *file); +#endif static void acpi_processor_notify(struct acpi_device *device, u32 event); static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); static int acpi_processor_handle_eject(struct acpi_processor *pr); @@ -110,7 +112,7 @@ static struct acpi_driver acpi_processor_driver = { #define INSTALL_NOTIFY_HANDLER 1 #define UNINSTALL_NOTIFY_HANDLER 2 - +#ifdef CONFIG_ACPI_PROCFS static const struct file_operations acpi_processor_info_fops = { .owner = THIS_MODULE, .open = acpi_processor_info_open_fs, @@ -118,6 +120,7 @@ static const struct file_operations acpi_processor_info_fops = { .llseek = seq_lseek, .release = single_release, }; +#endif DEFINE_PER_CPU(struct acpi_processor *, processors); struct acpi_processor_errata errata __read_mostly; @@ -316,6 +319,7 @@ static int acpi_processor_set_pdc(struct acpi_processor *pr) FS Interface (/proc) -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS static struct proc_dir_entry *acpi_processor_dir = NULL; static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset) @@ -388,7 +392,6 @@ static int acpi_processor_add_fs(struct acpi_device *device) return -EIO; return 0; } - static int acpi_processor_remove_fs(struct acpi_device *device) { @@ -405,6 +408,16 @@ static int acpi_processor_remove_fs(struct acpi_device *device) return 0; } +#else +static inline int acpi_processor_add_fs(struct acpi_device *device) +{ + return 0; +} +static inline int acpi_processor_remove_fs(struct acpi_device *device) +{ + return 0; +} +#endif /* Use the acpiid in MADT to map cpus in case of SMP */ @@ -1147,11 +1160,11 @@ static int __init acpi_processor_init(void) (struct acpi_table_header **)&madt))) madt = NULL; #endif - +#ifdef CONFIG_ACPI_PROCFS acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); if (!acpi_processor_dir) return -ENOMEM; - +#endif /* * Check whether the system is DMI table. If yes, OSPM * should not use mwait for CPU-states. @@ -1179,7 +1192,9 @@ out_cpuidle: cpuidle_unregister_driver(&acpi_idle_driver); out_proc: +#ifdef CONFIG_ACPI_PROCFS remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); +#endif return result; } @@ -1196,7 +1211,9 @@ static void __exit acpi_processor_exit(void) cpuidle_unregister_driver(&acpi_idle_driver); +#ifdef CONFIG_ACPI_PROCFS remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); +#endif return; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 10a2d913635a..67b2fa1b5b63 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -679,6 +679,7 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) return 0; } +#ifdef CONFIG_ACPI_PROCFS static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) { struct acpi_processor *pr = seq->private; @@ -758,7 +759,7 @@ static const struct file_operations acpi_processor_power_fops = { .llseek = seq_lseek, .release = single_release, }; - +#endif /** * acpi_idle_bm_check - checks if bus master activity was detected @@ -1216,7 +1217,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, pr->power.states[i].type); printk(")\n"); } - +#ifdef CONFIG_ACPI_PROCFS /* 'power' [R] */ entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER, S_IRUGO, acpi_device_dir(device), @@ -1224,6 +1225,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, acpi_driver_data(device)); if (!entry) return -EIO; +#endif return 0; } @@ -1236,9 +1238,11 @@ int acpi_processor_power_exit(struct acpi_processor *pr, cpuidle_unregister_device(&pr->power.dev); pr->flags.power_setup_done = 0; +#ifdef CONFIG_ACPI_PROCFS if (acpi_device_dir(device)) remove_proc_entry(ACPI_PROCESSOR_FILE_POWER, acpi_device_dir(device)); +#endif return 0; } diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 39838c666032..07e26140e977 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -438,7 +438,7 @@ struct thermal_cooling_device_ops processor_cooling_ops = { }; /* /proc interface */ - +#ifdef CONFIG_ACPI_PROCFS static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) { struct acpi_processor *pr = (struct acpi_processor *)seq->private; @@ -517,3 +517,4 @@ const struct file_operations acpi_processor_limit_fops = { .llseek = seq_lseek, .release = single_release, }; +#endif diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 227543789ba9..16560014f7bd 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -1214,7 +1214,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) } /* proc interface */ - +#ifdef CONFIG_ACPI_PROCFS static int acpi_processor_throttling_seq_show(struct seq_file *seq, void *offset) { @@ -1322,3 +1322,4 @@ const struct file_operations acpi_processor_throttling_fops = { .llseek = seq_lseek, .release = single_release, }; +#endif -- cgit v1.2.3-59-g8ed1b From b188e4ce3b7965ecc8d45191042cc9d25f6b90ee Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 24 Jun 2009 01:48:32 -0400 Subject: ACPI: fix CONFIG_ACPI_PROCFS=n build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/acpi/processor_idle.c:1162: warning: unused variable ‘entry’ Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 67b2fa1b5b63..b85d9f022716 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1160,7 +1160,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, { acpi_status status = 0; static int first_run; +#ifdef CONFIG_ACPI_PROCFS struct proc_dir_entry *entry = NULL; +#endif unsigned int i; if (boot_option_idle_override) -- cgit v1.2.3-59-g8ed1b From c1815e074079838d36d89e45e92b7ee317190700 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:04 +0000 Subject: ACPI: processor: remove KOBJ_ONLINE/KOBJ_OFFLINE events This patch removes the KOBJ_ONLINE/KOBJ_OFFLINE events the driver used to generate for CPU hotplug. As far as I know, nobody consumes these. The driver core still generates KOBJ_ADD and KOBJ_REMOVE, of course. Signed-off-by: Bjorn Helgaas CC: Venkatesh Pallipadi CC: Zhao Yakui CC: Matthew Garrett CC: Thomas Renninger CC: Dave Jones CC: Kay Sievers CC: Greg Kroah-Hartman Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 84e0f3c07442..c6ec68d4f165 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -963,9 +963,6 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) if (!pr) return -ENODEV; - if ((pr->id >= 0) && (pr->id < nr_cpu_ids)) { - kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE); - } return 0; } @@ -1002,18 +999,10 @@ static void __ref acpi_processor_hotplug_notify(acpi_handle handle, break; } - if (pr->id >= 0 && (pr->id < nr_cpu_ids)) { - kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); - break; - } - result = acpi_processor_start(device); - if ((!result) && ((pr->id >= 0) && (pr->id < nr_cpu_ids))) { - kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); - } else { + if (result) printk(KERN_ERR PREFIX "Device [%s] failed to start\n", acpi_device_bid(device)); - } break; case ACPI_NOTIFY_EJECT_REQUEST: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -1030,9 +1019,6 @@ static void __ref acpi_processor_hotplug_notify(acpi_handle handle, "Driver data is NULL, dropping EJECT\n"); return; } - - if ((pr->id < nr_cpu_ids) && (cpu_present(pr->id))) - kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, -- cgit v1.2.3-59-g8ed1b From d4e0526184199e23ac1460fe59b8a3741b17a8b5 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:09 +0000 Subject: ACPI: processor: clean up in acpi_processor_start() error exits We used to leave crud around if things failed in acpi_processor_start(). This patch cleans up as much as we can before returning. Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Chiang CC: Venkatesh Pallipadi CC: Zhao Yakui Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index c6ec68d4f165..a496a863edea 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -731,11 +731,13 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) result = acpi_processor_add_fs(device); if (result) - goto end; + return result; sysdev = get_cpu_sysdev(pr->id); - if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) - return -EFAULT; + if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { + result = -EFAULT; + goto err_remove_fs; + } /* _PDC call should be done before doing anything else (if reqd.). */ arch_acpi_processor_init_pdc(pr); @@ -755,7 +757,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) &processor_cooling_ops); if (IS_ERR(pr->cdev)) { result = PTR_ERR(pr->cdev); - goto end; + goto err_power_exit; } dev_info(&device->dev, "registered as cooling_device%d\n", @@ -764,13 +766,17 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, "thermal_cooling"); - if (result) + if (result) { printk(KERN_ERR PREFIX "Create sysfs link\n"); + goto err_thermal_unregister; + } result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, "device"); - if (result) + if (result) { printk(KERN_ERR PREFIX "Create sysfs link\n"); + goto err_remove_sysfs; + } if (pr->flags.throttling) { printk(KERN_INFO PREFIX "%s [%s] (supports", @@ -779,7 +785,16 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) printk(")\n"); } - end: + return 0; + +err_remove_sysfs: + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); +err_thermal_unregister: + thermal_cooling_device_unregister(pr->cdev); +err_power_exit: + acpi_processor_power_exit(pr, device); +err_remove_fs: + acpi_processor_remove_fs(device); return result; } -- cgit v1.2.3-59-g8ed1b From ddcd62d89e8c919cc75aeffd2ca37c986141b0f0 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:14 +0000 Subject: ACPI: processor: move acpi_processor_start() after acpi_processor_add() Move acpi_processor_start() to just after acpi_processor_add(). A subsequent patch will merge them. Code movement only; no functional change. Signed-off-by: Bjorn Helgaas CC: Venkatesh Pallipadi CC: Zhao Yakui Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 168 +++++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index a496a863edea..53de55e6f6b1 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -698,6 +698,90 @@ static int acpi_processor_get_info(struct acpi_device *device) static DEFINE_PER_CPU(void *, processor_device_array); +static void acpi_processor_notify(struct acpi_device *device, u32 event) +{ + struct acpi_processor *pr = acpi_driver_data(device); + int saved; + + if (!pr) + return; + + 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, + dev_name(&device->dev), event, + pr->performance_platform_limit); + break; + case ACPI_PROCESSOR_NOTIFY_POWER: + acpi_processor_cst_has_changed(pr); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + dev_name(&device->dev), event, 0); + break; + case ACPI_PROCESSOR_NOTIFY_THROTTLING: + acpi_processor_tstate_has_changed(pr); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + dev_name(&device->dev), event, 0); + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + return; +} + +static int acpi_cpu_soft_notify(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct acpi_processor *pr = per_cpu(processors, cpu); + + if (action == CPU_ONLINE && pr) { + acpi_processor_ppc_has_changed(pr); + acpi_processor_cst_has_changed(pr); + acpi_processor_tstate_has_changed(pr); + } + return NOTIFY_OK; +} + +static struct notifier_block acpi_cpu_notifier = +{ + .notifier_call = acpi_cpu_soft_notify, +}; + +static int acpi_processor_add(struct acpi_device *device) +{ + struct acpi_processor *pr = NULL; + + + if (!device) + return -EINVAL; + + pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); + if (!pr) + return -ENOMEM; + + if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { + kfree(pr); + return -ENOMEM; + } + + pr->handle = device->handle; + strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); + device->driver_data = pr; + + return 0; +} + static int __cpuinit acpi_processor_start(struct acpi_device *device) { int result = 0; @@ -799,90 +883,6 @@ err_remove_fs: return result; } -static void acpi_processor_notify(struct acpi_device *device, u32 event) -{ - struct acpi_processor *pr = acpi_driver_data(device); - int saved; - - if (!pr) - return; - - 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, - dev_name(&device->dev), event, - pr->performance_platform_limit); - break; - case ACPI_PROCESSOR_NOTIFY_POWER: - acpi_processor_cst_has_changed(pr); - acpi_bus_generate_proc_event(device, event, 0); - acpi_bus_generate_netlink_event(device->pnp.device_class, - dev_name(&device->dev), event, 0); - break; - case ACPI_PROCESSOR_NOTIFY_THROTTLING: - acpi_processor_tstate_has_changed(pr); - acpi_bus_generate_proc_event(device, event, 0); - acpi_bus_generate_netlink_event(device->pnp.device_class, - dev_name(&device->dev), event, 0); - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Unsupported event [0x%x]\n", event)); - break; - } - - return; -} - -static int acpi_cpu_soft_notify(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - struct acpi_processor *pr = per_cpu(processors, cpu); - - if (action == CPU_ONLINE && pr) { - acpi_processor_ppc_has_changed(pr); - acpi_processor_cst_has_changed(pr); - acpi_processor_tstate_has_changed(pr); - } - return NOTIFY_OK; -} - -static struct notifier_block acpi_cpu_notifier = -{ - .notifier_call = acpi_cpu_soft_notify, -}; - -static int acpi_processor_add(struct acpi_device *device) -{ - struct acpi_processor *pr = NULL; - - - if (!device) - return -EINVAL; - - pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); - if (!pr) - return -ENOMEM; - - if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { - kfree(pr); - return -ENOMEM; - } - - pr->handle = device->handle; - strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); - device->driver_data = pr; - - return 0; -} - static int acpi_processor_remove(struct acpi_device *device, int type) { struct acpi_processor *pr = NULL; -- cgit v1.2.3-59-g8ed1b From 970b04929a68134acca17878b1d93e115e58c12a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:19 +0000 Subject: ACPI: processor: remove .start() method This patch folds the .start() method into .add(). acpi_processor_start() is always called immediately after acpi_processor_add(), so there's really no point in having them be separate methods. Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Chiang CC: Venkatesh Pallipadi CC: Zhao Yakui Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 44 +++++++------------------------------------ 1 file changed, 7 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 53de55e6f6b1..8014e2a3b261 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -79,7 +79,6 @@ MODULE_DESCRIPTION("ACPI Processor Driver"); MODULE_LICENSE("GPL"); static int acpi_processor_add(struct acpi_device *device); -static int acpi_processor_start(struct acpi_device *device); static int acpi_processor_remove(struct acpi_device *device, int type); static int acpi_processor_info_open_fs(struct inode *inode, struct file *file); static void acpi_processor_notify(struct acpi_device *device, u32 event); @@ -101,7 +100,6 @@ static struct acpi_driver acpi_processor_driver = { .ops = { .add = acpi_processor_add, .remove = acpi_processor_remove, - .start = acpi_processor_start, .suspend = acpi_processor_suspend, .resume = acpi_processor_resume, .notify = acpi_processor_notify, @@ -760,10 +758,8 @@ static struct notifier_block acpi_cpu_notifier = static int acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; - - - if (!device) - return -EINVAL; + int result = 0; + struct sys_device *sysdev; pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); if (!pr) @@ -779,17 +775,6 @@ static int acpi_processor_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); device->driver_data = pr; - return 0; -} - -static int __cpuinit acpi_processor_start(struct acpi_device *device) -{ - int result = 0; - struct acpi_processor *pr; - struct sys_device *sysdev; - - pr = acpi_driver_data(device); - result = acpi_processor_get_info(device); if (result) { /* Processor is physically not present */ @@ -807,7 +792,8 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) per_cpu(processor_device_array, pr->id) != device) { printk(KERN_WARNING "BIOS reported wrong ACPI id " "for the processor\n"); - return -ENODEV; + result = -ENODEV; + goto err_free_cpumask; } per_cpu(processor_device_array, pr->id) = device; @@ -815,7 +801,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) result = acpi_processor_add_fs(device); if (result) - return result; + goto err_free_cpumask; sysdev = get_cpu_sysdev(pr->id); if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { @@ -879,6 +865,8 @@ err_power_exit: acpi_processor_power_exit(pr, device); err_remove_fs: acpi_processor_remove_fs(device); +err_free_cpumask: + free_cpumask_var(pr->throttling.shared_cpu_map); return result; } @@ -957,7 +945,6 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) { acpi_handle phandle; struct acpi_device *pdev; - struct acpi_processor *pr; if (acpi_get_parent(handle, &phandle)) { @@ -972,12 +959,6 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) return -ENODEV; } - acpi_bus_start(*device); - - pr = acpi_driver_data(*device); - if (!pr) - return -ENODEV; - return 0; } @@ -1007,17 +988,6 @@ static void __ref acpi_processor_hotplug_notify(acpi_handle handle, "Unable to add the device\n"); break; } - - pr = acpi_driver_data(device); - if (!pr) { - printk(KERN_ERR PREFIX "Driver data is NULL\n"); - break; - } - - result = acpi_processor_start(device); - if (result) - printk(KERN_ERR PREFIX "Device [%s] failed to start\n", - acpi_device_bid(device)); break; case ACPI_NOTIFY_EJECT_REQUEST: ACPI_DEBUG_PRINT((ACPI_DB_INFO, -- cgit v1.2.3-59-g8ed1b From 80f20fef6a2381402e59b169eb51b989cc175ab7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:25 +0000 Subject: ACPI: memory hotplug: remove .start() method This patch folds the .start() method into .add(). The .start() method is called in two paths: boot-time device enumeration and run-time node addition, currently via container_device_add(). In both cases, .start() is called immediately after .add(), so there's no reason to make them separate methods. Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Chiang CC: Yasunori Goto CC: Dave Hansen Signed-off-by: Len Brown --- drivers/acpi/acpi_memhotplug.c | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 7a0f4aa4fa1e..a8d9d8fac5d4 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -50,7 +50,6 @@ MODULE_LICENSE("GPL"); static int acpi_memory_device_add(struct acpi_device *device); static int acpi_memory_device_remove(struct acpi_device *device, int type); -static int acpi_memory_device_start(struct acpi_device *device); static const struct acpi_device_id memory_device_ids[] = { {ACPI_MEMORY_DEVICE_HID, 0}, @@ -65,7 +64,6 @@ static struct acpi_driver acpi_memory_device_driver = { .ops = { .add = acpi_memory_device_add, .remove = acpi_memory_device_remove, - .start = acpi_memory_device_start, }, }; @@ -415,28 +413,6 @@ static int acpi_memory_device_add(struct acpi_device *device) printk(KERN_DEBUG "%s \n", acpi_device_name(device)); - return result; -} - -static int acpi_memory_device_remove(struct acpi_device *device, int type) -{ - struct acpi_memory_device *mem_device = NULL; - - - if (!device || !acpi_driver_data(device)) - return -EINVAL; - - mem_device = acpi_driver_data(device); - kfree(mem_device); - - return 0; -} - -static int acpi_memory_device_start (struct acpi_device *device) -{ - struct acpi_memory_device *mem_device; - int result = 0; - /* * Early boot code has recognized memory area by EFI/E820. * If DSDT shows these memory devices on boot, hotplug is not necessary @@ -446,8 +422,6 @@ static int acpi_memory_device_start (struct acpi_device *device) if (!acpi_hotmem_initialized) return 0; - mem_device = acpi_driver_data(device); - if (!acpi_memory_check_device(mem_device)) { /* call add_memory func */ result = acpi_memory_enable_device(mem_device); @@ -458,6 +432,20 @@ static int acpi_memory_device_start (struct acpi_device *device) return result; } +static int acpi_memory_device_remove(struct acpi_device *device, int type) +{ + struct acpi_memory_device *mem_device = NULL; + + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + mem_device = acpi_driver_data(device); + kfree(mem_device); + + return 0; +} + /* * Helper function to check for memory device */ -- cgit v1.2.3-59-g8ed1b From 5efc5476184173996dfcce780c2bb5e727df674e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:30 +0000 Subject: ACPI: EC: move acpi_ec_start() after acpi_ec_add() This patch rearranges ec_install_handlers() and acpi_ec_start() so acpi_ec_start() ends up just after acpi_ec_add(). A subsequent patch will merge them. Code movement only; no functional change. Signed-off-by: Bjorn Helgaas CC: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 112 +++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 391f331674c7..8b387a48e843 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -788,6 +788,42 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) return AE_CTRL_TERMINATE; } +static int ec_install_handlers(struct acpi_ec *ec) +{ + acpi_status status; + if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) + return 0; + status = acpi_install_gpe_handler(NULL, ec->gpe, + ACPI_GPE_EDGE_TRIGGERED, + &acpi_ec_gpe_handler, ec); + if (ACPI_FAILURE(status)) + return -ENODEV; + acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec->gpe); + status = acpi_install_address_space_handler(ec->handle, + ACPI_ADR_SPACE_EC, + &acpi_ec_space_handler, + NULL, ec); + if (ACPI_FAILURE(status)) { + if (status == AE_NOT_FOUND) { + /* + * Maybe OS fails in evaluating the _REG object. + * The AE_NOT_FOUND error will be ignored and OS + * continue to initialize EC. + */ + printk(KERN_ERR "Fail in evaluating the _REG object" + " of EC device. Broken bios is suspected.\n"); + } else { + acpi_remove_gpe_handler(NULL, ec->gpe, + &acpi_ec_gpe_handler); + return -ENODEV; + } + } + + set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); + return 0; +} + static void ec_remove_handlers(struct acpi_ec *ec) { if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, @@ -842,6 +878,26 @@ static int acpi_ec_add(struct acpi_device *device) return 0; } +static int acpi_ec_start(struct acpi_device *device) +{ + struct acpi_ec *ec; + int ret = 0; + + if (!device) + return -EINVAL; + + ec = acpi_driver_data(device); + + if (!ec) + return -EINVAL; + + ret = ec_install_handlers(ec); + + /* EC is fully operational, allow queries */ + clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + return ret; +} + static int acpi_ec_remove(struct acpi_device *device, int type) { struct acpi_ec *ec; @@ -888,62 +944,6 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) return AE_OK; } -static int ec_install_handlers(struct acpi_ec *ec) -{ - acpi_status status; - if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) - return 0; - status = acpi_install_gpe_handler(NULL, ec->gpe, - ACPI_GPE_EDGE_TRIGGERED, - &acpi_ec_gpe_handler, ec); - if (ACPI_FAILURE(status)) - return -ENODEV; - acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); - acpi_enable_gpe(NULL, ec->gpe); - status = acpi_install_address_space_handler(ec->handle, - ACPI_ADR_SPACE_EC, - &acpi_ec_space_handler, - NULL, ec); - if (ACPI_FAILURE(status)) { - if (status == AE_NOT_FOUND) { - /* - * Maybe OS fails in evaluating the _REG object. - * The AE_NOT_FOUND error will be ignored and OS - * continue to initialize EC. - */ - printk(KERN_ERR "Fail in evaluating the _REG object" - " of EC device. Broken bios is suspected.\n"); - } else { - acpi_remove_gpe_handler(NULL, ec->gpe, - &acpi_ec_gpe_handler); - return -ENODEV; - } - } - - set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); - return 0; -} - -static int acpi_ec_start(struct acpi_device *device) -{ - struct acpi_ec *ec; - int ret = 0; - - if (!device) - return -EINVAL; - - ec = acpi_driver_data(device); - - if (!ec) - return -EINVAL; - - ret = ec_install_handlers(ec); - - /* EC is fully operational, allow queries */ - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - return ret; -} - static int acpi_ec_stop(struct acpi_device *device, int type) { struct acpi_ec *ec; -- cgit v1.2.3-59-g8ed1b From d02be04707b8ff5375a76c027327e8708877da39 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:35 +0000 Subject: ACPI: EC: remove .start() method This patch folds the .start() method into .add(). acpi_ec_start() is always called immediately after acpi_ec_add(), so there's no need to have it be a separate method. Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Chiang CC: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 8b387a48e843..1feedcea2d40 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -838,9 +838,8 @@ static void ec_remove_handlers(struct acpi_ec *ec) static int acpi_ec_add(struct acpi_device *device) { struct acpi_ec *ec = NULL; + int ret; - if (!device) - return -EINVAL; strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); @@ -875,21 +874,6 @@ static int acpi_ec_add(struct acpi_device *device) ec->gpe, ec->command_addr, ec->data_addr); pr_info(PREFIX "driver started in %s mode\n", (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll"); - return 0; -} - -static int acpi_ec_start(struct acpi_device *device) -{ - struct acpi_ec *ec; - int ret = 0; - - if (!device) - return -EINVAL; - - ec = acpi_driver_data(device); - - if (!ec) - return -EINVAL; ret = ec_install_handlers(ec); @@ -1077,7 +1061,6 @@ static struct acpi_driver acpi_ec_driver = { .ops = { .add = acpi_ec_add, .remove = acpi_ec_remove, - .start = acpi_ec_start, .stop = acpi_ec_stop, .suspend = acpi_ec_suspend, .resume = acpi_ec_resume, -- cgit v1.2.3-59-g8ed1b From cf745ec7a1222a661b2c5f0e8c2c4be81300d2a4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:40 +0000 Subject: ACPI: EC: remove .stop() method This patch folds the .stop() method into .remove(). acpi_ec_stop() is only called via acpi_device_probe() and acpi_device_remove(), and in both cases it is called immediately before acpi_ec_remove(), so there's no need to have it be a separate method. Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Chiang CC: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 1feedcea2d40..d6bf0578737b 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -891,6 +891,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type) return -EINVAL; ec = acpi_driver_data(device); + ec_remove_handlers(ec); mutex_lock(&ec->lock); list_for_each_entry_safe(handler, tmp, &ec->list, node) { list_del(&handler->node); @@ -928,19 +929,6 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) return AE_OK; } -static int acpi_ec_stop(struct acpi_device *device, int type) -{ - struct acpi_ec *ec; - if (!device) - return -EINVAL; - ec = acpi_driver_data(device); - if (!ec) - return -EINVAL; - ec_remove_handlers(ec); - - return 0; -} - int __init acpi_boot_ec_enable(void) { if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags)) @@ -1061,7 +1049,6 @@ static struct acpi_driver acpi_ec_driver = { .ops = { .add = acpi_ec_add, .remove = acpi_ec_remove, - .stop = acpi_ec_stop, .suspend = acpi_ec_suspend, .resume = acpi_ec_resume, }, -- cgit v1.2.3-59-g8ed1b From dcf52fb71d988ba945054308f661bddf9b2455fb Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 22 Jun 2009 20:41:45 +0000 Subject: ACPI: remove unused acpi_device_ops .stop method No drivers use the .stop method, so remove it. Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Chiang Signed-off-by: Len Brown --- drivers/acpi/scan.c | 5 ----- include/acpi/acpi_bus.h | 2 -- 2 files changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 781435d7e369..4a89f081160f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -426,9 +426,6 @@ static int acpi_device_probe(struct device * dev) if (acpi_drv->ops.notify) { ret = acpi_device_install_notify_handler(acpi_dev); if (ret) { - if (acpi_drv->ops.stop) - acpi_drv->ops.stop(acpi_dev, - acpi_dev->removal_type); if (acpi_drv->ops.remove) acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); @@ -452,8 +449,6 @@ static int acpi_device_remove(struct device * dev) if (acpi_drv) { if (acpi_drv->ops.notify) acpi_device_remove_notify_handler(acpi_dev); - if (acpi_drv->ops.stop) - acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type); if (acpi_drv->ops.remove) acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c65e4ce6c3af..79a6c5ebe908 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -89,7 +89,6 @@ struct acpi_device; typedef int (*acpi_op_add) (struct acpi_device * device); typedef int (*acpi_op_remove) (struct acpi_device * device, int type); typedef int (*acpi_op_start) (struct acpi_device * device); -typedef int (*acpi_op_stop) (struct acpi_device * device, int type); typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state); typedef int (*acpi_op_resume) (struct acpi_device * device); @@ -106,7 +105,6 @@ struct acpi_device_ops { acpi_op_add add; acpi_op_remove remove; acpi_op_start start; - acpi_op_stop stop; acpi_op_suspend suspend; acpi_op_resume resume; acpi_op_bind bind; -- cgit v1.2.3-59-g8ed1b From 5853a9f6dda244b4163b9daad663bdc41a74f596 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 2 Jun 2009 13:20:00 +0800 Subject: ACPICA: Fix several pointer casts to avoid possible compile warnings Fixes warnings with gcc -Wcast-qual flag. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/exdump.c | 6 +++--- drivers/acpi/acpica/nsutils.c | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index ec524614e708..de3446372ddc 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -418,9 +418,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, case ACPI_EXD_REFERENCE: acpi_ex_out_string("Class Name", - (char *) - acpi_ut_get_reference_name - (obj_desc)); + ACPI_CAST_PTR(char, + acpi_ut_get_reference_name + (obj_desc))); acpi_ex_dump_reference_obj(obj_desc); break; diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 78277ed08339..ea55ab4f9849 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -88,7 +88,8 @@ acpi_ns_report_error(const char *module_name, /* There is a non-ascii character in the name */ - ACPI_MOVE_32_TO_32(&bad_name, internal_name); + ACPI_MOVE_32_TO_32(&bad_name, + ACPI_CAST_PTR(u32, internal_name)); acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name); } else { /* Convert path to external format */ @@ -836,7 +837,7 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node, acpi_status status; char *internal_path; - ACPI_FUNCTION_TRACE_PTR(ns_get_node, pathname); + ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname)); if (!pathname) { *return_node = prefix_node; -- cgit v1.2.3-59-g8ed1b From f8d80cdf40fe4d2393159012b38ce9f85a488686 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 2 Jun 2009 13:28:13 +0800 Subject: ACPICA: Remove duplicate extern declarations for public globals Some were defined twice, causes a warning with gcc -Wredundant-decls. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acglobal.h | 33 ++++++++++++++++++--------------- include/acpi/acpixf.h | 1 + 2 files changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 3d87362d17ed..0b73b31c1b53 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -58,6 +58,10 @@ #define ACPI_INIT_GLOBAL(a,b) a #endif +#ifdef DEFINE_ACPI_GLOBALS + +/* Public globals, available from outside ACPICA subsystem */ + /***************************************************************************** * * Runtime configuration (static defaults that can be overriden at runtime) @@ -78,7 +82,7 @@ * 5) Allow unresolved references (invalid target name) in package objects * 6) Enable warning messages for behavior that is not ACPI spec compliant */ -ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE); +u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE); /* * Automatically serialize ALL control methods? Default is FALSE, meaning @@ -86,27 +90,36 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE); * Only change this if the ASL code is poorly written and cannot handle * reentrancy even though methods are marked "NotSerialized". */ -ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE); +u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE); /* * Create the predefined _OSI method in the namespace? Default is TRUE * because ACPI CA is fully compatible with other ACPI implementations. * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior. */ -ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE); +u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE); /* * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only * be enabled just before going to sleep. */ -ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); +u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); /* * Optionally use default values for the ACPI register widths. Set this to * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. */ -ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); +u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); + +/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ + +struct acpi_table_fadt acpi_gbl_FADT; +u32 acpi_current_gpe_count; +u32 acpi_gbl_trace_flags; +acpi_name acpi_gbl_trace_method_name; + +#endif /***************************************************************************** * @@ -114,11 +127,6 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); * ****************************************************************************/ -/* Runtime configuration of debug print levels */ - -extern u32 acpi_dbg_level; -extern u32 acpi_dbg_layer; - /* Procedure nesting level for debug output */ extern u32 acpi_gbl_nesting_level; @@ -127,10 +135,8 @@ extern u32 acpi_gbl_nesting_level; ACPI_EXTERN u32 acpi_gbl_original_dbg_level; ACPI_EXTERN u32 acpi_gbl_original_dbg_layer; -ACPI_EXTERN acpi_name acpi_gbl_trace_method_name; ACPI_EXTERN u32 acpi_gbl_trace_dbg_level; ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer; -ACPI_EXTERN u32 acpi_gbl_trace_flags; /***************************************************************************** * @@ -142,10 +148,8 @@ ACPI_EXTERN u32 acpi_gbl_trace_flags; * acpi_gbl_root_table_list is the master list of ACPI tables found in the * RSDT/XSDT. * - * acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list; -ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT; ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS; /* These addresses are calculated from the FADT Event Block addresses */ @@ -340,7 +344,6 @@ ACPI_EXTERN struct acpi_fixed_event_handler ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head; ACPI_EXTERN struct acpi_gpe_block_info *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]; -ACPI_EXTERN u32 acpi_current_gpe_count; /***************************************************************************** * diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 82ec6a3c0500..2aecaa5cc06c 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -64,6 +64,7 @@ extern u8 acpi_gbl_enable_interpreter_slack; extern u8 acpi_gbl_all_methods_serialized; extern u8 acpi_gbl_create_osi_method; extern u8 acpi_gbl_leave_wake_gpes_disabled; +extern u8 acpi_gbl_use_default_register_widths; extern acpi_name acpi_gbl_trace_method_name; extern u32 acpi_gbl_trace_flags; -- cgit v1.2.3-59-g8ed1b From c6b5774caafa4c12b6019366e2fdaaff117e95a4 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 24 Jun 2009 09:44:06 +0800 Subject: ACPICA: Add 64-bit support to acpi_read and acpi_write Needed by drivers for new ACPi tables. Internal versions of these functions still use 32-bit max transfers, in order to minimize disruption and stack use for the standard ACPI registers (FADT-based). Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/achware.h | 8 ++ drivers/acpi/acpica/evgpe.c | 8 +- drivers/acpi/acpica/evgpeblk.c | 4 +- drivers/acpi/acpica/hwgpe.c | 34 +++---- drivers/acpi/acpica/hwregs.c | 206 ++++++++++++++++++++++++++++++++++++++--- drivers/acpi/acpica/hwtimer.c | 2 +- drivers/acpi/acpica/hwxface.c | 166 +++++++++++++++++++-------------- include/acpi/acpixf.h | 4 +- 8 files changed, 327 insertions(+), 105 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 4afa3d8e0efb..36192f142fbb 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -62,6 +62,14 @@ u32 acpi_hw_get_mode(void); /* * hwregs - ACPI Register I/O */ +acpi_status +acpi_hw_validate_register(struct acpi_generic_address *reg, + u8 max_bit_width, u64 *address); + +acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg); + +acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg); + struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id); acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control); diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index b9d8ee69ca6c..afacf4416c73 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -424,8 +424,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* Read the Status Register */ status = - acpi_read(&status_reg, - &gpe_register_info->status_address); + acpi_hw_read(&status_reg, + &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -433,8 +433,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* Read the Enable Register */ status = - acpi_read(&enable_reg, - &gpe_register_info->enable_address); + acpi_hw_read(&enable_reg, + &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 7b3463639422..a60aaa7635f3 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -843,14 +843,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* Disable all GPEs within this register */ - status = acpi_write(0x00, &this_register->enable_address); + status = acpi_hw_write(0x00, &this_register->enable_address); if (ACPI_FAILURE(status)) { goto error_exit; } /* Clear any pending GPE events within this register */ - status = acpi_write(0xFF, &this_register->status_address); + status = acpi_hw_write(0xFF, &this_register->status_address); if (ACPI_FAILURE(status)) { goto error_exit; } diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index d3b7e37c9eed..c28c41b3180b 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -82,7 +82,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) /* Get current value of the enable register that contains this GPE */ - status = acpi_read(&enable_mask, &gpe_register_info->enable_address); + status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -95,7 +95,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) /* Write the updated enable mask */ - status = acpi_write(enable_mask, &gpe_register_info->enable_address); + status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); return (status); } @@ -130,8 +130,8 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info) /* Write the entire GPE (runtime) enable register */ - status = acpi_write(gpe_register_info->enable_for_run, - &gpe_register_info->enable_address); + status = acpi_hw_write(gpe_register_info->enable_for_run, + &gpe_register_info->enable_address); return (status); } @@ -163,8 +163,8 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) * Write a one to the appropriate bit in the status register to * clear this GPE. */ - status = acpi_write(register_bit, - &gpe_event_info->register_info->status_address); + status = acpi_hw_write(register_bit, + &gpe_event_info->register_info->status_address); return (status); } @@ -222,7 +222,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, /* GPE currently active (status bit == 1)? */ - status = acpi_read(&in_byte, &gpe_register_info->status_address); + status = acpi_hw_read(&in_byte, &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -266,8 +266,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* Disable all GPEs in this register */ status = - acpi_write(0x00, - &gpe_block->register_info[i].enable_address); + acpi_hw_write(0x00, + &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -303,8 +303,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* Clear status on all GPEs in this register */ status = - acpi_write(0xFF, - &gpe_block->register_info[i].status_address); + acpi_hw_write(0xFF, + &gpe_block->register_info[i].status_address); if (ACPI_FAILURE(status)) { return (status); } @@ -345,9 +345,9 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* Enable all "runtime" GPEs in this register */ - status = acpi_write(gpe_block->register_info[i].enable_for_run, - &gpe_block->register_info[i]. - enable_address); + status = + acpi_hw_write(gpe_block->register_info[i].enable_for_run, + &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -387,9 +387,9 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* Enable all "wake" GPEs in this register */ - status = acpi_write(gpe_block->register_info[i].enable_for_wake, - &gpe_block->register_info[i]. - enable_address); + status = + acpi_hw_write(gpe_block->register_info[i].enable_for_wake, + &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE(status)) { return (status); } diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 23d5505cb1f7..15c9ed2be853 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -62,6 +62,184 @@ acpi_hw_write_multiple(u32 value, struct acpi_generic_address *register_a, struct acpi_generic_address *register_b); +/****************************************************************************** + * + * FUNCTION: acpi_hw_validate_register + * + * PARAMETERS: Reg - GAS register structure + * max_bit_width - Max bit_width supported (32 or 64) + * Address - Pointer to where the gas->address + * is returned + * + * RETURN: Status + * + * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS + * pointer, Address, space_id, bit_width, and bit_offset. + * + ******************************************************************************/ + +acpi_status +acpi_hw_validate_register(struct acpi_generic_address *reg, + u8 max_bit_width, u64 *address) +{ + + /* Must have a valid pointer to a GAS structure */ + + if (!reg) { + return (AE_BAD_PARAMETER); + } + + /* + * Copy the target address. This handles possible alignment issues. + * Address must not be null. A null address also indicates an optional + * ACPI register that is not supported, so no error message. + */ + ACPI_MOVE_64_TO_64(address, ®->address); + if (!(*address)) { + return (AE_BAD_ADDRESS); + } + + /* Validate the space_iD */ + + if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + ACPI_ERROR((AE_INFO, + "Unsupported address space: 0x%X", reg->space_id)); + return (AE_SUPPORT); + } + + /* Validate the bit_width */ + + if ((reg->bit_width != 8) && + (reg->bit_width != 16) && + (reg->bit_width != 32) && (reg->bit_width != max_bit_width)) { + ACPI_ERROR((AE_INFO, + "Unsupported register bit width: 0x%X", + reg->bit_width)); + return (AE_SUPPORT); + } + + /* Validate the bit_offset. Just a warning for now. */ + + if (reg->bit_offset != 0) { + ACPI_WARNING((AE_INFO, + "Unsupported register bit offset: 0x%X", + reg->bit_offset)); + } + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_hw_read + * + * PARAMETERS: Value - Where the value is returned + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max + * version of acpi_read, used internally since the overhead of + * 64-bit values is not needed. + * + * LIMITATIONS: + * bit_width must be exactly 8, 16, or 32. + * space_iD must be system_memory or system_iO. + * bit_offset and access_width are currently ignored, as there has + * not been a need to implement these. + * + ******************************************************************************/ + +acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) +{ + u64 address; + acpi_status status; + + ACPI_FUNCTION_NAME(hw_read); + + /* Validate contents of the GAS register */ + + status = acpi_hw_validate_register(reg, 32, &address); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Initialize entire 32-bit return value to zero */ + + *value = 0; + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + status = acpi_os_read_memory((acpi_physical_address) + address, value, reg->bit_width); + } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + + status = acpi_hw_read_port((acpi_io_address) + address, value, reg->bit_width); + } + + ACPI_DEBUG_PRINT((ACPI_DB_IO, + "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *value, reg->bit_width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); + + return (status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_hw_write + * + * PARAMETERS: Value - Value to be written + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max + * version of acpi_write, used internally since the overhead of + * 64-bit values is not needed. + * + ******************************************************************************/ + +acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) +{ + u64 address; + acpi_status status; + + ACPI_FUNCTION_NAME(hw_write); + + /* Validate contents of the GAS register */ + + status = acpi_hw_validate_register(reg, 32, &address); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + status = acpi_os_write_memory((acpi_physical_address) + address, value, reg->bit_width); + } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + + status = acpi_hw_write_port((acpi_io_address) + address, value, reg->bit_width); + } + + ACPI_DEBUG_PRINT((ACPI_DB_IO, + "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + value, reg->bit_width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); + + return (status); +} + /******************************************************************************* * * FUNCTION: acpi_hw_clear_acpi_status @@ -152,15 +330,16 @@ acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control) ACPI_FUNCTION_TRACE(hw_write_pm1_control); - status = acpi_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block); + status = + acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (acpi_gbl_FADT.xpm1b_control_block.address) { status = - acpi_write(pm1b_control, - &acpi_gbl_FADT.xpm1b_control_block); + acpi_hw_write(pm1b_control, + &acpi_gbl_FADT.xpm1b_control_block); } return_ACPI_STATUS(status); } @@ -218,12 +397,13 @@ acpi_hw_register_read(u32 register_id, u32 * return_value) case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ - status = acpi_read(&value, &acpi_gbl_FADT.xpm2_control_block); + status = + acpi_hw_read(&value, &acpi_gbl_FADT.xpm2_control_block); break; case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ - status = acpi_read(&value, &acpi_gbl_FADT.xpm_timer_block); + status = acpi_hw_read(&value, &acpi_gbl_FADT.xpm_timer_block); break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ @@ -340,7 +520,8 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value) * as per the ACPI spec. */ status = - acpi_read(&read_value, &acpi_gbl_FADT.xpm2_control_block); + acpi_hw_read(&read_value, + &acpi_gbl_FADT.xpm2_control_block); if (ACPI_FAILURE(status)) { goto exit; } @@ -350,12 +531,13 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value) ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS, read_value); - status = acpi_write(value, &acpi_gbl_FADT.xpm2_control_block); + status = + acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block); break; case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ - status = acpi_write(value, &acpi_gbl_FADT.xpm_timer_block); + status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block); break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ @@ -401,7 +583,7 @@ acpi_hw_read_multiple(u32 *value, /* The first register is always required */ - status = acpi_read(&value_a, register_a); + status = acpi_hw_read(&value_a, register_a); if (ACPI_FAILURE(status)) { return (status); } @@ -409,7 +591,7 @@ acpi_hw_read_multiple(u32 *value, /* Second register is optional */ if (register_b->address) { - status = acpi_read(&value_b, register_b); + status = acpi_hw_read(&value_b, register_b); if (ACPI_FAILURE(status)) { return (status); } @@ -452,7 +634,7 @@ acpi_hw_write_multiple(u32 value, /* The first register is always required */ - status = acpi_write(value, register_a); + status = acpi_hw_write(value, register_a); if (ACPI_FAILURE(status)) { return (status); } @@ -470,7 +652,7 @@ acpi_hw_write_multiple(u32 value, * and writes have no side effects" */ if (register_b->address) { - status = acpi_write(value, register_b); + status = acpi_hw_write(value, register_b); } return (status); diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index b7f522c8f023..6b282e85d039 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -100,7 +100,7 @@ acpi_status acpi_get_timer(u32 * ticks) } status = - acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block); + acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 9829979f2bdd..4ead85f29215 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -80,7 +80,7 @@ acpi_status acpi_reset(void) /* Write the reset value to the reset register */ - status = acpi_write(acpi_gbl_FADT.reset_value, reset_reg); + status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg); return_ACPI_STATUS(status); } @@ -97,67 +97,92 @@ ACPI_EXPORT_SYMBOL(acpi_reset) * * DESCRIPTION: Read from either memory or IO space. * + * LIMITATIONS: + * bit_width must be exactly 8, 16, 32, or 64. + * space_iD must be system_memory or system_iO. + * bit_offset and access_width are currently ignored, as there has + * not been a need to implement these. + * ******************************************************************************/ -acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg) +acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg) { + u32 value; u32 width; u64 address; acpi_status status; ACPI_FUNCTION_NAME(acpi_read); - /* - * Must have a valid pointer to a GAS structure, and a non-zero address - * within. - */ - if (!reg) { + if (!return_value) { return (AE_BAD_PARAMETER); } - /* Get a local copy of the address. Handles possible alignment issues */ + /* Validate contents of the GAS register. Allow 64-bit transfers */ - ACPI_MOVE_64_TO_64(&address, ®->address); - if (!address) { - return (AE_BAD_ADDRESS); + status = acpi_hw_validate_register(reg, 64, &address); + if (ACPI_FAILURE(status)) { + return (status); } - /* Supported widths are 8/16/32 */ - width = reg->bit_width; - if ((width != 8) && (width != 16) && (width != 32)) { - return (AE_SUPPORT); + if (width == 64) { + width = 32; /* Break into two 32-bit transfers */ } - /* Initialize entire 32-bit return value to zero */ + /* Initialize entire 64-bit return value to zero */ - *value = 0; + *return_value = 0; + value = 0; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ - switch (reg->space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + status = acpi_os_read_memory((acpi_physical_address) + address, &value, width); + if (ACPI_FAILURE(status)) { + return (status); + } + *return_value = value; + + if (reg->bit_width == 64) { - status = acpi_os_read_memory((acpi_physical_address) address, - value, width); - break; + /* Read the top 32 bits */ - case ACPI_ADR_SPACE_SYSTEM_IO: + status = acpi_os_read_memory((acpi_physical_address) + (address + 4), &value, 32); + if (ACPI_FAILURE(status)) { + return (status); + } + *return_value |= ((u64)value << 32); + } + } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ - status = - acpi_hw_read_port((acpi_io_address) address, value, width); - break; + status = acpi_hw_read_port((acpi_io_address) + address, &value, width); + if (ACPI_FAILURE(status)) { + return (status); + } + *return_value = value; - default: - ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", reg->space_id)); - return (AE_BAD_PARAMETER); + if (reg->bit_width == 64) { + + /* Read the top 32 bits */ + + status = acpi_hw_read_port((acpi_io_address) + (address + 4), &value, 32); + if (ACPI_FAILURE(status)) { + return (status); + } + *return_value |= ((u64)value << 32); + } } ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", - *value, width, ACPI_FORMAT_UINT64(address), + "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n", + ACPI_FORMAT_UINT64(*return_value), reg->bit_width, + ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); @@ -169,7 +194,7 @@ ACPI_EXPORT_SYMBOL(acpi_read) * * FUNCTION: acpi_write * - * PARAMETERS: Value - To be written + * PARAMETERS: Value - Value to be written * Reg - GAS register structure * * RETURN: Status @@ -177,7 +202,7 @@ ACPI_EXPORT_SYMBOL(acpi_read) * DESCRIPTION: Write to either memory or IO space. * ******************************************************************************/ -acpi_status acpi_write(u32 value, struct acpi_generic_address *reg) +acpi_status acpi_write(u64 value, struct acpi_generic_address *reg) { u32 width; u64 address; @@ -185,54 +210,61 @@ acpi_status acpi_write(u32 value, struct acpi_generic_address *reg) ACPI_FUNCTION_NAME(acpi_write); - /* - * Must have a valid pointer to a GAS structure, and a non-zero address - * within. - */ - if (!reg) { - return (AE_BAD_PARAMETER); - } + /* Validate contents of the GAS register. Allow 64-bit transfers */ - /* Get a local copy of the address. Handles possible alignment issues */ - - ACPI_MOVE_64_TO_64(&address, ®->address); - if (!address) { - return (AE_BAD_ADDRESS); + status = acpi_hw_validate_register(reg, 64, &address); + if (ACPI_FAILURE(status)) { + return (status); } - /* Supported widths are 8/16/32 */ - width = reg->bit_width; - if ((width != 8) && (width != 16) && (width != 32)) { - return (AE_SUPPORT); + if (width == 64) { + width = 32; /* Break into two 32-bit transfers */ } /* - * Two address spaces supported: Memory or IO. - * PCI_Config is not supported here because the GAS struct is insufficient + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient */ - switch (reg->space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - - status = acpi_os_write_memory((acpi_physical_address) address, - value, width); - break; + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + status = acpi_os_write_memory((acpi_physical_address) + address, ACPI_LODWORD(value), + width); + if (ACPI_FAILURE(status)) { + return (status); + } - case ACPI_ADR_SPACE_SYSTEM_IO: + if (reg->bit_width == 64) { + status = acpi_os_write_memory((acpi_physical_address) + (address + 4), + ACPI_HIDWORD(value), 32); + if (ACPI_FAILURE(status)) { + return (status); + } + } + } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ - status = acpi_hw_write_port((acpi_io_address) address, value, + status = acpi_hw_write_port((acpi_io_address) + address, ACPI_LODWORD(value), width); - break; + if (ACPI_FAILURE(status)) { + return (status); + } - default: - ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", reg->space_id)); - return (AE_BAD_PARAMETER); + if (reg->bit_width == 64) { + status = acpi_hw_write_port((acpi_io_address) + (address + 4), + ACPI_HIDWORD(value), 32); + if (ACPI_FAILURE(status)) { + return (status); + } + } } ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, width, ACPI_FORMAT_UINT64(address), + "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", + ACPI_FORMAT_UINT64(value), reg->bit_width, + ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 2aecaa5cc06c..b450a195319a 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -360,9 +360,9 @@ acpi_status acpi_set_firmware_waking_vector(u32 physical_address); acpi_status acpi_set_firmware_waking_vector64(u64 physical_address); #endif -acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg); +acpi_status acpi_read(u64 *value, struct acpi_generic_address *reg); -acpi_status acpi_write(u32 value, struct acpi_generic_address *reg); +acpi_status acpi_write(u64 value, struct acpi_generic_address *reg); acpi_status acpi_get_sleep_type_data(u8 sleep_state, u8 * slp_typ_a, u8 * slp_typ_b); -- cgit v1.2.3-59-g8ed1b From 9c61b34cf7078da72cce276ff8cfae5d6e9955bc Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 24 Jun 2009 09:45:17 +0800 Subject: ACPICA: Remove duplicate prototypes from header Two duplicates in acdebug.h. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acdebug.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 62c59df3b86c..a4fb001d96f1 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -154,10 +154,6 @@ void acpi_db_display_argument_object(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state); -void acpi_db_check_predefined_names(void); - -void acpi_db_batch_execute(void); - /* * dbexec - debugger control method execution */ -- cgit v1.2.3-59-g8ed1b From 15b8dd53f5ffaf8e2d9095c423f713423f576c0f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 29 Jun 2009 13:39:29 +0800 Subject: ACPICA: Major update for acpi_get_object_info external interface Completed a major update for the acpi_get_object_info external interface. Changes include: - Support for variable, unlimited length HID, UID, and CID strings - Support Processor objects the same as Devices (HID,UID,CID,ADR,STA, etc.) - Call the _SxW power methods on behalf of a device object - Determine if a device is a PCI root bridge - Change the ACPI_BUFFER parameter to ACPI_DEVICE_INFO. These changes will require an update to all callers of this interface. See the ACPICA Programmer Reference for details. Also, update all invocations of acpi_get_object_info interface Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- arch/ia64/hp/common/sba_iommu.c | 7 +- drivers/acpi/acpi_memhotplug.c | 11 +- drivers/acpi/acpica/Makefile | 2 +- drivers/acpi/acpica/acconfig.h | 5 + drivers/acpi/acpica/acglobal.h | 3 +- drivers/acpi/acpica/acinterp.h | 4 +- drivers/acpi/acpica/acutils.h | 24 ++- drivers/acpi/acpica/evrgnini.c | 45 +---- drivers/acpi/acpica/exutils.c | 53 +++-- drivers/acpi/acpica/nsdumpdv.c | 7 +- drivers/acpi/acpica/nsxfeval.c | 23 ++- drivers/acpi/acpica/nsxfname.c | 237 +++++++++++++++++------ drivers/acpi/acpica/uteval.c | 375 ++++-------------------------------- drivers/acpi/acpica/utglobal.c | 10 +- drivers/acpi/acpica/utids.c | 382 +++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/utmisc.c | 28 +++ drivers/acpi/container.c | 11 +- drivers/acpi/dock.c | 8 +- drivers/acpi/glue.c | 6 +- drivers/acpi/scan.c | 153 +++++++++------ drivers/char/agp/hp-agp.c | 9 +- drivers/ide/ide-acpi.c | 5 +- drivers/pci/hotplug/acpiphp_ibm.c | 12 +- drivers/platform/x86/sony-laptop.c | 7 +- drivers/pnp/pnpacpi/core.c | 6 +- include/acpi/acpi_bus.h | 8 +- include/acpi/acpixf.h | 3 +- include/acpi/actypes.h | 87 +++++---- 28 files changed, 901 insertions(+), 630 deletions(-) create mode 100644 drivers/acpi/acpica/utids.c (limited to 'drivers') diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 8cfb001092ab..674a8374c6d9 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -2026,24 +2026,21 @@ acpi_sba_ioc_add(struct acpi_device *device) struct ioc *ioc; acpi_status status; u64 hpa, length; - struct acpi_buffer buffer; struct acpi_device_info *dev_info; status = hp_acpi_csr_space(device->handle, &hpa, &length); if (ACPI_FAILURE(status)) return 1; - buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_get_object_info(device->handle, &buffer); + status = acpi_get_object_info(device->handle, &dev_info); if (ACPI_FAILURE(status)) return 1; - dev_info = buffer.pointer; /* * For HWP0001, only SBA appears in ACPI namespace. It encloses the PCI * root bridges, and its CSR space includes the IOC function. */ - if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0) { + if (strncmp("HWP0001", dev_info->hardware_id.string, 7) == 0) { hpa += ZX1_IOC_OFFSET; /* zx1 based systems default to kernel page size iommu pages */ if (!iovp_shift) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 9a62224cc278..80eacbe157e2 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -481,26 +481,23 @@ static acpi_status is_memory_device(acpi_handle handle) { char *hardware_id; acpi_status status; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_device_info *info; - - status = acpi_get_object_info(handle, &buffer); + status = acpi_get_object_info(handle, &info); if (ACPI_FAILURE(status)) return status; - info = buffer.pointer; if (!(info->valid & ACPI_VALID_HID)) { - kfree(buffer.pointer); + kfree(info); return AE_ERROR; } - hardware_id = info->hardware_id.value; + hardware_id = info->hardware_id.string; if ((hardware_id == NULL) || (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID))) status = AE_ERROR; - kfree(buffer.pointer); + kfree(info); return status; } diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 72ac28da14e3..0e7d56185f6d 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -44,4 +44,4 @@ acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ utcopy.o utdelete.o utglobal.o utmath.o utobject.o \ - utstate.o utmutex.o utobject.o utresrc.o utlock.o + utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index e6777fb883d2..6c1fb2d9f4d5 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -203,6 +203,11 @@ #define ACPI_SMBUS_BUFFER_SIZE 34 +/* _sx_d and _sx_w control methods */ + +#define ACPI_NUM_sx_d_METHODS 4 +#define ACPI_NUM_sx_w_METHODS 5 + /****************************************************************************** * * ACPI AML Debugger diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 0b73b31c1b53..6389f7c1de59 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -265,7 +265,8 @@ ACPI_EXTERN u8 acpi_gbl_osi_data; extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; -extern const char *acpi_gbl_highest_dstate_names[4]; +extern const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS]; +extern const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index e8db7a3143a5..5db9f2916f7c 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -461,9 +461,9 @@ void acpi_ex_acquire_global_lock(u32 rule); void acpi_ex_release_global_lock(u32 rule); -void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string); +void acpi_ex_eisa_id_to_string(char *dest, acpi_integer compressed_id); -void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string); +void acpi_ex_integer_to_string(char *dest, acpi_integer value); /* * exregion - default op_region handlers diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 897810ba0ccc..b0add85de308 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -324,26 +324,30 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, acpi_status acpi_ut_evaluate_numeric_object(char *object_name, struct acpi_namespace_node *device_node, - acpi_integer * address); + acpi_integer *value); acpi_status -acpi_ut_execute_HID(struct acpi_namespace_node *device_node, - struct acpica_device_id *hid); +acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 *status_flags); acpi_status -acpi_ut_execute_CID(struct acpi_namespace_node *device_node, - struct acpi_compatible_id_list **return_cid_list); +acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, + const char **method_names, + u8 method_count, u8 *out_values); +/* + * utids - device ID support + */ acpi_status -acpi_ut_execute_STA(struct acpi_namespace_node *device_node, - u32 * status_flags); +acpi_ut_execute_HID(struct acpi_namespace_node *device_node, + struct acpica_device_id **return_id); acpi_status acpi_ut_execute_UID(struct acpi_namespace_node *device_node, - struct acpica_device_id *uid); + struct acpica_device_id **return_id); acpi_status -acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest); +acpi_ut_execute_CID(struct acpi_namespace_node *device_node, + struct acpica_device_id_list **return_cid_list); /* * utlock - reader/writer locks @@ -445,6 +449,8 @@ acpi_ut_short_divide(acpi_integer in_dividend, */ const char *acpi_ut_validate_exception(acpi_status status); +u8 acpi_ut_is_pci_root_bridge(char *id); + u8 acpi_ut_is_aml_table(struct acpi_table_header *table); acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id); diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 284a7becbe96..cf29c4953028 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -50,8 +50,6 @@ ACPI_MODULE_NAME("evrgnini") /* Local prototypes */ -static u8 acpi_ev_match_pci_root_bridge(char *id); - static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); /******************************************************************************* @@ -330,37 +328,6 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, return_ACPI_STATUS(AE_OK); } -/******************************************************************************* - * - * FUNCTION: acpi_ev_match_pci_root_bridge - * - * PARAMETERS: Id - The HID/CID in string format - * - * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge - * - * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID. - * - ******************************************************************************/ - -static u8 acpi_ev_match_pci_root_bridge(char *id) -{ - - /* - * Check if this is a PCI root. - * ACPI 3.0+: check for a PCI Express root also. - */ - if (!(ACPI_STRNCMP(id, - PCI_ROOT_HID_STRING, - sizeof(PCI_ROOT_HID_STRING))) || - !(ACPI_STRNCMP(id, - PCI_EXPRESS_ROOT_HID_STRING, - sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { - return (TRUE); - } - - return (FALSE); -} - /******************************************************************************* * * FUNCTION: acpi_ev_is_pci_root_bridge @@ -377,9 +344,10 @@ static u8 acpi_ev_match_pci_root_bridge(char *id) static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) { acpi_status status; - struct acpica_device_id hid; - struct acpi_compatible_id_list *cid; + struct acpica_device_id *hid; + struct acpica_device_id_list *cid; u32 i; + u8 match; /* Get the _HID and check for a PCI Root Bridge */ @@ -388,7 +356,10 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) return (FALSE); } - if (acpi_ev_match_pci_root_bridge(hid.value)) { + match = acpi_ut_is_pci_root_bridge(hid->string); + ACPI_FREE(hid); + + if (match) { return (TRUE); } @@ -402,7 +373,7 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) /* Check all _CIDs in the returned list */ for (i = 0; i < cid->count; i++) { - if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) { + if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) { ACPI_FREE(cid); return (TRUE); } diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 87730e944132..7d41f99f7052 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -358,50 +358,67 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base) * * FUNCTION: acpi_ex_eisa_id_to_string * - * PARAMETERS: numeric_id - EISA ID to be converted + * PARAMETERS: compressed_id - EISAID to be converted * out_string - Where to put the converted string (8 bytes) * * RETURN: None * - * DESCRIPTION: Convert a numeric EISA ID to string representation + * DESCRIPTION: Convert a numeric EISAID to string representation. Return + * buffer must be large enough to hold the string. The string + * returned is always exactly of length ACPI_EISAID_STRING_SIZE + * (includes null terminator). The EISAID is always 32 bits. * ******************************************************************************/ -void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string) +void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id) { - u32 eisa_id; + u32 swapped_id; ACPI_FUNCTION_ENTRY(); + /* The EISAID should be a 32-bit integer */ + + if (compressed_id > ACPI_UINT32_MAX) { + ACPI_WARNING((AE_INFO, + "Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating", + ACPI_FORMAT_UINT64(compressed_id))); + } + /* Swap ID to big-endian to get contiguous bits */ - eisa_id = acpi_ut_dword_byte_swap(numeric_id); + swapped_id = acpi_ut_dword_byte_swap((u32)compressed_id); - out_string[0] = (char)('@' + (((unsigned long)eisa_id >> 26) & 0x1f)); - out_string[1] = (char)('@' + ((eisa_id >> 21) & 0x1f)); - out_string[2] = (char)('@' + ((eisa_id >> 16) & 0x1f)); - out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 12); - out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 8); - out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 4); - out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 0); + /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */ + + out_string[0] = + (char)(0x40 + (((unsigned long)swapped_id >> 26) & 0x1F)); + out_string[1] = (char)(0x40 + ((swapped_id >> 21) & 0x1F)); + out_string[2] = (char)(0x40 + ((swapped_id >> 16) & 0x1F)); + out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 12); + out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 8); + out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 4); + out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 0); out_string[7] = 0; } /******************************************************************************* * - * FUNCTION: acpi_ex_unsigned_integer_to_string + * FUNCTION: acpi_ex_integer_to_string * - * PARAMETERS: Value - Value to be converted - * out_string - Where to put the converted string (8 bytes) + * PARAMETERS: out_string - Where to put the converted string. At least + * 21 bytes are needed to hold the largest + * possible 64-bit integer. + * Value - Value to be converted * * RETURN: None, string * - * DESCRIPTION: Convert a number to string representation. Assumes string - * buffer is large enough to hold the string. + * DESCRIPTION: Convert a 64-bit integer to decimal string representation. + * Assumes string buffer is large enough to hold the string. The + * largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1). * ******************************************************************************/ -void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string) +void acpi_ex_integer_to_string(char *out_string, acpi_integer value) { u32 count; u32 digits_needed; diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 41994fe7fbb8..0fe87f1aef16 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -70,7 +70,6 @@ static acpi_status acpi_ns_dump_one_device(acpi_handle obj_handle, u32 level, void *context, void **return_value) { - struct acpi_buffer buffer; struct acpi_device_info *info; acpi_status status; u32 i; @@ -80,17 +79,15 @@ acpi_ns_dump_one_device(acpi_handle obj_handle, status = acpi_ns_dump_one_object(obj_handle, level, context, return_value); - buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_get_object_info(obj_handle, &buffer); + status = acpi_get_object_info(obj_handle, &info); if (ACPI_SUCCESS(status)) { - info = buffer.pointer; for (i = 0; i < level; i++) { ACPI_DEBUG_PRINT_RAW((ACPI_DB_TABLES, " ")); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_TABLES, " HID: %s, ADR: %8.8X%8.8X, Status: %X\n", - info->hardware_id.value, + info->hardware_id.string, ACPI_FORMAT_UINT64(info->address), info->current_status)); ACPI_FREE(info); diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index daf4ad37896d..4929dbdbc8f0 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -535,10 +535,11 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, acpi_status status; struct acpi_namespace_node *node; u32 flags; - struct acpica_device_id hid; - struct acpi_compatible_id_list *cid; + struct acpica_device_id *hid; + struct acpica_device_id_list *cid; u32 i; - int found; + u8 found; + int no_match; status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { @@ -582,10 +583,14 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, return (AE_CTRL_DEPTH); } - if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) { - - /* Get the list of Compatible IDs */ + no_match = ACPI_STRCMP(hid->string, info->hid); + ACPI_FREE(hid); + if (no_match) { + /* + * HID does not match, attempt match within the + * list of Compatible IDs (CIDs) + */ status = acpi_ut_execute_CID(node, &cid); if (status == AE_NOT_FOUND) { return (AE_OK); @@ -597,10 +602,8 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, found = 0; for (i = 0; i < cid->count; i++) { - if (ACPI_STRNCMP(cid->id[i].value, info->hid, - sizeof(struct - acpi_compatible_id)) == - 0) { + if (ACPI_STRCMP(cid->ids[i].string, info->hid) + == 0) { found = 1; break; } diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index f23593d6add4..ddc84af6336e 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -51,6 +51,11 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfname") +/* Local prototypes */ +static char *acpi_ns_copy_device_id(struct acpica_device_id *dest, + struct acpica_device_id *source, + char *string_area); + /****************************************************************************** * * FUNCTION: acpi_get_handle @@ -68,6 +73,7 @@ ACPI_MODULE_NAME("nsxfname") * namespace handle. * ******************************************************************************/ + acpi_status acpi_get_handle(acpi_handle parent, acpi_string pathname, acpi_handle * ret_handle) @@ -208,12 +214,40 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) ACPI_EXPORT_SYMBOL(acpi_get_name) +/****************************************************************************** + * + * FUNCTION: acpi_ns_copy_device_id + * + * PARAMETERS: Dest - Pointer to the destination DEVICE_ID + * Source - Pointer to the source DEVICE_ID + * string_area - Pointer to where to copy the dest string + * + * RETURN: Pointer to the next string area + * + * DESCRIPTION: Copy a single DEVICE_ID, including the string data. + * + ******************************************************************************/ +static char *acpi_ns_copy_device_id(struct acpica_device_id *dest, + struct acpica_device_id *source, + char *string_area) +{ + /* Create the destination DEVICE_ID */ + + dest->string = string_area; + dest->length = source->length; + + /* Copy actual string and return a pointer to the next string area */ + + ACPI_MEMCPY(string_area, source->string, source->length); + return (string_area + source->length); +} + /****************************************************************************** * * FUNCTION: acpi_get_object_info * - * PARAMETERS: Handle - Object Handle - * Buffer - Where the info is returned + * PARAMETERS: Handle - Object Handle + * return_buffer - Where the info is returned * * RETURN: Status * @@ -221,33 +255,37 @@ ACPI_EXPORT_SYMBOL(acpi_get_name) * namespace node and possibly by running several standard * control methods (Such as in the case of a device.) * + * For Device and Processor objects, run the Device _HID, _UID, _CID, _STA, + * _ADR, _sx_w, and _sx_d methods. + * + * Note: Allocates the return buffer, must be freed by the caller. + * ******************************************************************************/ + acpi_status -acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) +acpi_get_object_info(acpi_handle handle, + struct acpi_device_info **return_buffer) { - acpi_status status; struct acpi_namespace_node *node; struct acpi_device_info *info; - struct acpi_device_info *return_info; - struct acpi_compatible_id_list *cid_list = NULL; - acpi_size size; + struct acpica_device_id_list *cid_list = NULL; + struct acpica_device_id *hid = NULL; + struct acpica_device_id *uid = NULL; + char *next_id_string; + acpi_object_type type; + acpi_name name; + u8 param_count = 0; + u8 valid = 0; + u32 info_size; + u32 i; + acpi_status status; /* Parameter validation */ - if (!handle || !buffer) { + if (!handle || !return_buffer) { return (AE_BAD_PARAMETER); } - status = acpi_ut_validate_buffer(buffer); - if (ACPI_FAILURE(status)) { - return (status); - } - - info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_device_info)); - if (!info) { - return (AE_NO_MEMORY); - } - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto cleanup; @@ -256,66 +294,91 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) node = acpi_ns_map_handle_to_node(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - status = AE_BAD_PARAMETER; - goto cleanup; + return (AE_BAD_PARAMETER); } - /* Init return structure */ - - size = sizeof(struct acpi_device_info); + /* Get the namespace node data while the namespace is locked */ - info->type = node->type; - info->name = node->name.integer; - info->valid = 0; + info_size = sizeof(struct acpi_device_info); + type = node->type; + name = node->name.integer; if (node->type == ACPI_TYPE_METHOD) { - info->param_count = node->object->method.param_count; + param_count = node->object->method.param_count; } status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - goto cleanup; + return (status); } - /* If not a device, we are all done */ - - if (info->type == ACPI_TYPE_DEVICE) { + if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { /* - * Get extra info for ACPI Devices objects only: - * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. + * Get extra info for ACPI Device/Processor objects only: + * Run the Device _HID, _UID, and _CID methods. * * Note: none of these methods are required, so they may or may - * not be present for this device. The Info->Valid bitfield is used - * to indicate which methods were found and ran successfully. + * not be present for this device. The Info->Valid bitfield is used + * to indicate which methods were found and run successfully. */ /* Execute the Device._HID method */ - status = acpi_ut_execute_HID(node, &info->hardware_id); + status = acpi_ut_execute_HID(node, &hid); if (ACPI_SUCCESS(status)) { - info->valid |= ACPI_VALID_HID; + info_size += hid->length; + valid |= ACPI_VALID_HID; } /* Execute the Device._UID method */ - status = acpi_ut_execute_UID(node, &info->unique_id); + status = acpi_ut_execute_UID(node, &uid); if (ACPI_SUCCESS(status)) { - info->valid |= ACPI_VALID_UID; + info_size += uid->length; + valid |= ACPI_VALID_UID; } /* Execute the Device._CID method */ status = acpi_ut_execute_CID(node, &cid_list); if (ACPI_SUCCESS(status)) { - size += cid_list->size; - info->valid |= ACPI_VALID_CID; + + /* Add size of CID strings and CID pointer array */ + + info_size += + (cid_list->list_size - + sizeof(struct acpica_device_id_list)); + valid |= ACPI_VALID_CID; } + } + + /* + * Now that we have the variable-length data, we can allocate the + * return buffer + */ + info = ACPI_ALLOCATE_ZEROED(info_size); + if (!info) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Get the fixed-length data */ + + if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { + /* + * Get extra info for ACPI Device/Processor objects only: + * Run the _STA, _ADR and, sx_w, and _sx_d methods. + * + * Note: none of these methods are required, so they may or may + * not be present for this device. The Info->Valid bitfield is used + * to indicate which methods were found and run successfully. + */ /* Execute the Device._STA method */ status = acpi_ut_execute_STA(node, &info->current_status); if (ACPI_SUCCESS(status)) { - info->valid |= ACPI_VALID_STA; + valid |= ACPI_VALID_STA; } /* Execute the Device._ADR method */ @@ -323,36 +386,100 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node, &info->address); if (ACPI_SUCCESS(status)) { - info->valid |= ACPI_VALID_ADR; + valid |= ACPI_VALID_ADR; + } + + /* Execute the Device._sx_w methods */ + + status = acpi_ut_execute_power_methods(node, + acpi_gbl_lowest_dstate_names, + ACPI_NUM_sx_w_METHODS, + info->lowest_dstates); + if (ACPI_SUCCESS(status)) { + valid |= ACPI_VALID_SXWS; } /* Execute the Device._sx_d methods */ - status = acpi_ut_execute_sxds(node, info->highest_dstates); + status = acpi_ut_execute_power_methods(node, + acpi_gbl_highest_dstate_names, + ACPI_NUM_sx_d_METHODS, + info->highest_dstates); if (ACPI_SUCCESS(status)) { - info->valid |= ACPI_VALID_SXDS; + valid |= ACPI_VALID_SXDS; } } - /* Validate/Allocate/Clear caller buffer */ + /* + * Create a pointer to the string area of the return buffer. + * Point to the end of the base struct acpi_device_info structure. + */ + next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids); + if (cid_list) { - status = acpi_ut_initialize_buffer(buffer, size); - if (ACPI_FAILURE(status)) { - goto cleanup; + /* Point past the CID DEVICE_ID array */ + + next_id_string += + ((acpi_size) cid_list->count * + sizeof(struct acpica_device_id)); } - /* Populate the return buffer */ + /* + * Copy the HID, UID, and CIDs to the return buffer. The variable-length + * strings are copied to the reserved area at the end of the buffer. + * + * For HID and CID, check if the ID is a PCI Root Bridge. + */ + if (hid) { + next_id_string = acpi_ns_copy_device_id(&info->hardware_id, + hid, next_id_string); + + if (acpi_ut_is_pci_root_bridge(hid->string)) { + info->flags |= ACPI_PCI_ROOT_BRIDGE; + } + } - return_info = buffer->pointer; - ACPI_MEMCPY(return_info, info, sizeof(struct acpi_device_info)); + if (uid) { + next_id_string = acpi_ns_copy_device_id(&info->unique_id, + uid, next_id_string); + } if (cid_list) { - ACPI_MEMCPY(&return_info->compatibility_id, cid_list, - cid_list->size); + info->compatible_id_list.count = cid_list->count; + info->compatible_id_list.list_size = cid_list->list_size; + + /* Copy each CID */ + + for (i = 0; i < cid_list->count; i++) { + next_id_string = + acpi_ns_copy_device_id(&info->compatible_id_list. + ids[i], &cid_list->ids[i], + next_id_string); + + if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) { + info->flags |= ACPI_PCI_ROOT_BRIDGE; + } + } } + /* Copy the fixed-length data */ + + info->info_size = info_size; + info->type = type; + info->name = name; + info->param_count = param_count; + info->valid = valid; + + *return_buffer = info; + status = AE_OK; + cleanup: - ACPI_FREE(info); + if (hid) { + ACPI_FREE(hid); + } + if (uid) { + ACPI_FREE(uid); + } if (cid_list) { ACPI_FREE(cid_list); } diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 006b16c26017..5503307b8bb7 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -44,19 +44,10 @@ #include #include "accommon.h" #include "acnamesp.h" -#include "acinterp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("uteval") -/* Local prototypes */ -static void -acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length); - -static acpi_status -acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, - struct acpi_compatible_id *one_cid); - /* * Strings supported by the _OSI predefined (internal) method. * @@ -213,7 +204,7 @@ acpi_status acpi_osi_invalidate(char *interface) * RETURN: Status * * DESCRIPTION: Evaluates a namespace object and verifies the type of the - * return object. Common code that simplifies accessing objects + * return object. Common code that simplifies accessing objects * that have required return objects of fixed types. * * NOTE: Internal function, no parameter validation @@ -298,7 +289,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, if ((acpi_gbl_enable_interpreter_slack) && (!expected_return_btypes)) { /* - * We received a return object, but one was not expected. This can + * We received a return object, but one was not expected. This can * happen frequently if the "implicit return" feature is enabled. * Just delete the return object and return AE_OK. */ @@ -340,12 +331,12 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, * * PARAMETERS: object_name - Object name to be evaluated * device_node - Node for the device - * Address - Where the value is returned + * Value - Where the value is returned * * RETURN: Status * * DESCRIPTION: Evaluates a numeric namespace object for a selected device - * and stores result in *Address. + * and stores result in *Value. * * NOTE: Internal function, no parameter validation * @@ -354,7 +345,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, acpi_status acpi_ut_evaluate_numeric_object(char *object_name, struct acpi_namespace_node *device_node, - acpi_integer * address) + acpi_integer *value) { union acpi_operand_object *obj_desc; acpi_status status; @@ -369,295 +360,7 @@ acpi_ut_evaluate_numeric_object(char *object_name, /* Get the returned Integer */ - *address = obj_desc->integer.value; - - /* On exit, we must delete the return object */ - - acpi_ut_remove_reference(obj_desc); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_copy_id_string - * - * PARAMETERS: Destination - Where to copy the string - * Source - Source string - * max_length - Length of the destination buffer - * - * RETURN: None - * - * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods. - * Performs removal of a leading asterisk if present -- workaround - * for a known issue on a bunch of machines. - * - ******************************************************************************/ - -static void -acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length) -{ - - /* - * Workaround for ID strings that have a leading asterisk. This construct - * is not allowed by the ACPI specification (ID strings must be - * alphanumeric), but enough existing machines have this embedded in their - * ID strings that the following code is useful. - */ - if (*source == '*') { - source++; - } - - /* Do the actual copy */ - - ACPI_STRNCPY(destination, source, max_length); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_execute_HID - * - * PARAMETERS: device_node - Node for the device - * Hid - Where the HID is returned - * - * RETURN: Status - * - * DESCRIPTION: Executes the _HID control method that returns the hardware - * ID of the device. - * - * NOTE: Internal function, no parameter validation - * - ******************************************************************************/ - -acpi_status -acpi_ut_execute_HID(struct acpi_namespace_node *device_node, - struct acpica_device_id *hid) -{ - union acpi_operand_object *obj_desc; - acpi_status status; - - ACPI_FUNCTION_TRACE(ut_execute_HID); - - status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID, - ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, - &obj_desc); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - if (obj_desc->common.type == ACPI_TYPE_INTEGER) { - - /* Convert the Numeric HID to string */ - - acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value, - hid->value); - } else { - /* Copy the String HID from the returned object */ - - acpi_ut_copy_id_string(hid->value, obj_desc->string.pointer, - sizeof(hid->value)); - } - - /* On exit, we must delete the return object */ - - acpi_ut_remove_reference(obj_desc); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_translate_one_cid - * - * PARAMETERS: obj_desc - _CID object, must be integer or string - * one_cid - Where the CID string is returned - * - * RETURN: Status - * - * DESCRIPTION: Return a numeric or string _CID value as a string. - * (Compatible ID) - * - * NOTE: Assumes a maximum _CID string length of - * ACPI_MAX_CID_LENGTH. - * - ******************************************************************************/ - -static acpi_status -acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, - struct acpi_compatible_id *one_cid) -{ - - switch (obj_desc->common.type) { - case ACPI_TYPE_INTEGER: - - /* Convert the Numeric CID to string */ - - acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value, - one_cid->value); - return (AE_OK); - - case ACPI_TYPE_STRING: - - if (obj_desc->string.length > ACPI_MAX_CID_LENGTH) { - return (AE_AML_STRING_LIMIT); - } - - /* Copy the String CID from the returned object */ - - acpi_ut_copy_id_string(one_cid->value, obj_desc->string.pointer, - ACPI_MAX_CID_LENGTH); - return (AE_OK); - - default: - - return (AE_TYPE); - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_execute_CID - * - * PARAMETERS: device_node - Node for the device - * return_cid_list - Where the CID list is returned - * - * RETURN: Status - * - * DESCRIPTION: Executes the _CID control method that returns one or more - * compatible hardware IDs for the device. - * - * NOTE: Internal function, no parameter validation - * - ******************************************************************************/ - -acpi_status -acpi_ut_execute_CID(struct acpi_namespace_node * device_node, - struct acpi_compatible_id_list ** return_cid_list) -{ - union acpi_operand_object *obj_desc; - acpi_status status; - u32 count; - u32 size; - struct acpi_compatible_id_list *cid_list; - u32 i; - - ACPI_FUNCTION_TRACE(ut_execute_CID); - - /* Evaluate the _CID method for this device */ - - status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID, - ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING - | ACPI_BTYPE_PACKAGE, &obj_desc); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the number of _CIDs returned */ - - count = 1; - if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { - count = obj_desc->package.count; - } - - /* Allocate a worst-case buffer for the _CIDs */ - - size = (((count - 1) * sizeof(struct acpi_compatible_id)) + - sizeof(struct acpi_compatible_id_list)); - - cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size); - if (!cid_list) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Init CID list */ - - cid_list->count = count; - cid_list->size = size; - - /* - * A _CID can return either a single compatible ID or a package of - * compatible IDs. Each compatible ID can be one of the following: - * 1) Integer (32 bit compressed EISA ID) or - * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") - */ - - /* The _CID object can be either a single CID or a package (list) of CIDs */ - - if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { - - /* Translate each package element */ - - for (i = 0; i < count; i++) { - status = - acpi_ut_translate_one_cid(obj_desc->package. - elements[i], - &cid_list->id[i]); - if (ACPI_FAILURE(status)) { - break; - } - } - } else { - /* Only one CID, translate to a string */ - - status = acpi_ut_translate_one_cid(obj_desc, cid_list->id); - } - - /* Cleanup on error */ - - if (ACPI_FAILURE(status)) { - ACPI_FREE(cid_list); - } else { - *return_cid_list = cid_list; - } - - /* On exit, we must delete the _CID return object */ - - acpi_ut_remove_reference(obj_desc); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_execute_UID - * - * PARAMETERS: device_node - Node for the device - * Uid - Where the UID is returned - * - * RETURN: Status - * - * DESCRIPTION: Executes the _UID control method that returns the hardware - * ID of the device. - * - * NOTE: Internal function, no parameter validation - * - ******************************************************************************/ - -acpi_status -acpi_ut_execute_UID(struct acpi_namespace_node *device_node, - struct acpica_device_id *uid) -{ - union acpi_operand_object *obj_desc; - acpi_status status; - - ACPI_FUNCTION_TRACE(ut_execute_UID); - - status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID, - ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, - &obj_desc); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - if (obj_desc->common.type == ACPI_TYPE_INTEGER) { - - /* Convert the Numeric UID to string */ - - acpi_ex_unsigned_integer_to_string(obj_desc->integer.value, - uid->value); - } else { - /* Copy the String UID from the returned object */ - - acpi_ut_copy_id_string(uid->value, obj_desc->string.pointer, - sizeof(uid->value)); - } + *value = obj_desc->integer.value; /* On exit, we must delete the return object */ @@ -716,60 +419,64 @@ acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags) /******************************************************************************* * - * FUNCTION: acpi_ut_execute_Sxds + * FUNCTION: acpi_ut_execute_power_methods * * PARAMETERS: device_node - Node for the device - * Flags - Where the status flags are returned + * method_names - Array of power method names + * method_count - Number of methods to execute + * out_values - Where the power method values are returned * - * RETURN: Status + * RETURN: Status, out_values * - * DESCRIPTION: Executes _STA for selected device and stores results in - * *Flags. + * DESCRIPTION: Executes the specified power methods for the device and returns + * the result(s). * * NOTE: Internal function, no parameter validation * - ******************************************************************************/ +******************************************************************************/ acpi_status -acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest) +acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, + const char **method_names, + u8 method_count, u8 *out_values) { union acpi_operand_object *obj_desc; acpi_status status; + acpi_status final_status = AE_NOT_FOUND; u32 i; - ACPI_FUNCTION_TRACE(ut_execute_sxds); + ACPI_FUNCTION_TRACE(ut_execute_power_methods); - for (i = 0; i < 4; i++) { - highest[i] = 0xFF; + for (i = 0; i < method_count; i++) { + /* + * Execute the power method (_sx_d or _sx_w). The only allowable + * return type is an Integer. + */ status = acpi_ut_evaluate_object(device_node, ACPI_CAST_PTR(char, - acpi_gbl_highest_dstate_names - [i]), + method_names[i]), ACPI_BTYPE_INTEGER, &obj_desc); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "%s on Device %4.4s, %s\n", - ACPI_CAST_PTR(char, - acpi_gbl_highest_dstate_names - [i]), - acpi_ut_get_node_name - (device_node), - acpi_format_exception - (status))); - - return_ACPI_STATUS(status); - } - } else { - /* Extract the Dstate value */ - - highest[i] = (u8) obj_desc->integer.value; + if (ACPI_SUCCESS(status)) { + out_values[i] = (u8)obj_desc->integer.value; /* Delete the return object */ acpi_ut_remove_reference(obj_desc); + final_status = AE_OK; /* At least one value is valid */ + continue; } + + out_values[i] = ACPI_UINT8_MAX; + if (status == AE_NOT_FOUND) { + continue; /* Ignore if not found */ + } + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Failed %s on Device %4.4s, %s\n", + ACPI_CAST_PTR(char, method_names[i]), + acpi_ut_get_node_name(device_node), + acpi_format_exception(status))); } - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(final_status); } diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 59e46f257c02..ed7a33c67fbe 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -90,7 +90,15 @@ const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { "\\_S5_" }; -const char *acpi_gbl_highest_dstate_names[4] = { +const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS] = { + "_S0W", + "_S1W", + "_S2W", + "_S3W", + "_S4W" +}; + +const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS] = { "_S1D", "_S2D", "_S3D", diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c new file mode 100644 index 000000000000..52eaae404554 --- /dev/null +++ b/drivers/acpi/acpica/utids.c @@ -0,0 +1,382 @@ +/****************************************************************************** + * + * Module Name: utids - support for device IDs - HID, UID, CID + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2009, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utids") + +/* Local prototypes */ +static void acpi_ut_copy_id_string(char *destination, char *source); + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_id_string + * + * PARAMETERS: Destination - Where to copy the string + * Source - Source string + * + * RETURN: None + * + * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods. + * Performs removal of a leading asterisk if present -- workaround + * for a known issue on a bunch of machines. + * + ******************************************************************************/ + +static void acpi_ut_copy_id_string(char *destination, char *source) +{ + + /* + * Workaround for ID strings that have a leading asterisk. This construct + * is not allowed by the ACPI specification (ID strings must be + * alphanumeric), but enough existing machines have this embedded in their + * ID strings that the following code is useful. + */ + if (*source == '*') { + source++; + } + + /* Do the actual copy */ + + ACPI_STRCPY(destination, source); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_HID + * + * PARAMETERS: device_node - Node for the device + * return_id - Where the string HID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _HID control method that returns the hardware + * ID of the device. The HID is either an 32-bit encoded EISAID + * Integer or a String. A string is always returned. An EISAID + * is converted to a string. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_HID(struct acpi_namespace_node *device_node, + struct acpica_device_id **return_id) +{ + union acpi_operand_object *obj_desc; + struct acpica_device_id *hid; + u32 length; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_execute_HID); + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, + &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Get the size of the String to be returned, includes null terminator */ + + if (obj_desc->common.type == ACPI_TYPE_INTEGER) { + length = ACPI_EISAID_STRING_SIZE; + } else { + length = obj_desc->string.length + 1; + } + + /* Allocate a buffer for the HID */ + + hid = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) + + (acpi_size) length); + if (!hid) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Area for the string starts after DEVICE_ID struct */ + + hid->string = ACPI_ADD_PTR(char, hid, sizeof(struct acpica_device_id)); + + /* Convert EISAID to a string or simply copy existing string */ + + if (obj_desc->common.type == ACPI_TYPE_INTEGER) { + acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value); + } else { + acpi_ut_copy_id_string(hid->string, obj_desc->string.pointer); + } + + hid->length = length; + *return_id = hid; + +cleanup: + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_UID + * + * PARAMETERS: device_node - Node for the device + * return_id - Where the string UID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _UID control method that returns the unique + * ID of the device. The UID is either a 64-bit Integer (NOT an + * EISAID) or a string. Always returns a string. A 64-bit integer + * is converted to a decimal string. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_UID(struct acpi_namespace_node *device_node, + struct acpica_device_id **return_id) +{ + union acpi_operand_object *obj_desc; + struct acpica_device_id *uid; + u32 length; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_execute_UID); + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, + &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Get the size of the String to be returned, includes null terminator */ + + if (obj_desc->common.type == ACPI_TYPE_INTEGER) { + length = ACPI_MAX64_DECIMAL_DIGITS + 1; + } else { + length = obj_desc->string.length + 1; + } + + /* Allocate a buffer for the UID */ + + uid = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) + + (acpi_size) length); + if (!uid) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Area for the string starts after DEVICE_ID struct */ + + uid->string = ACPI_ADD_PTR(char, uid, sizeof(struct acpica_device_id)); + + /* Convert an Integer to string, or just copy an existing string */ + + if (obj_desc->common.type == ACPI_TYPE_INTEGER) { + acpi_ex_integer_to_string(uid->string, obj_desc->integer.value); + } else { + acpi_ut_copy_id_string(uid->string, obj_desc->string.pointer); + } + + uid->length = length; + *return_id = uid; + +cleanup: + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_CID + * + * PARAMETERS: device_node - Node for the device + * return_cid_list - Where the CID list is returned + * + * RETURN: Status, list of CID strings + * + * DESCRIPTION: Executes the _CID control method that returns one or more + * compatible hardware IDs for the device. + * + * NOTE: Internal function, no parameter validation + * + * A _CID method can return either a single compatible ID or a package of + * compatible IDs. Each compatible ID can be one of the following: + * 1) Integer (32 bit compressed EISA ID) or + * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") + * + * The Integer CIDs are converted to string format by this function. + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_CID(struct acpi_namespace_node *device_node, + struct acpica_device_id_list **return_cid_list) +{ + union acpi_operand_object **cid_objects; + union acpi_operand_object *obj_desc; + struct acpica_device_id_list *cid_list; + char *next_id_string; + u32 string_area_size; + u32 length; + u32 cid_list_size; + acpi_status status; + u32 count; + u32 i; + + ACPI_FUNCTION_TRACE(ut_execute_CID); + + /* Evaluate the _CID method for this device */ + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING + | ACPI_BTYPE_PACKAGE, &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* + * Get the count and size of the returned _CIDs. _CID can return either + * a Package of Integers/Strings or a single Integer or String. + * Note: This section also validates that all CID elements are of the + * correct type (Integer or String). + */ + if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { + count = obj_desc->package.count; + cid_objects = obj_desc->package.elements; + } else { /* Single Integer or String CID */ + + count = 1; + cid_objects = &obj_desc; + } + + string_area_size = 0; + for (i = 0; i < count; i++) { + + /* String lengths include null terminator */ + + switch (cid_objects[i]->common.type) { + case ACPI_TYPE_INTEGER: + string_area_size += ACPI_EISAID_STRING_SIZE; + break; + + case ACPI_TYPE_STRING: + string_area_size += cid_objects[i]->string.length + 1; + break; + + default: + status = AE_TYPE; + goto cleanup; + } + } + + /* + * Now that we know the length of the CIDs, allocate return buffer: + * 1) Size of the base structure + + * 2) Size of the CID DEVICE_ID array + + * 3) Size of the actual CID strings + */ + cid_list_size = sizeof(struct acpica_device_id_list) + + ((count - 1) * sizeof(struct acpica_device_id)) + string_area_size; + + cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size); + if (!cid_list) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Area for CID strings starts after the CID DEVICE_ID array */ + + next_id_string = ACPI_CAST_PTR(char, cid_list->ids) + + ((acpi_size) count * sizeof(struct acpica_device_id)); + + /* Copy/convert the CIDs to the return buffer */ + + for (i = 0; i < count; i++) { + if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) { + + /* Convert the Integer (EISAID) CID to a string */ + + acpi_ex_eisa_id_to_string(next_id_string, + cid_objects[i]->integer. + value); + length = ACPI_EISAID_STRING_SIZE; + } else { /* ACPI_TYPE_STRING */ + + /* Copy the String CID from the returned object */ + + acpi_ut_copy_id_string(next_id_string, + cid_objects[i]->string.pointer); + length = cid_objects[i]->string.length + 1; + } + + cid_list->ids[i].string = next_id_string; + cid_list->ids[i].length = length; + next_id_string += length; + } + + /* Finish the CID list */ + + cid_list->count = count; + cid_list->list_size = cid_list_size; + *return_cid_list = cid_list; + +cleanup: + + /* On exit, we must delete the _CID return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index fbe782348b0b..9cd65334ca75 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -118,6 +118,34 @@ const char *acpi_ut_validate_exception(acpi_status status) return (ACPI_CAST_PTR(const char, exception)); } +/******************************************************************************* + * + * FUNCTION: acpi_ut_is_pci_root_bridge + * + * PARAMETERS: Id - The HID/CID in string format + * + * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge + * + * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID. + * + ******************************************************************************/ + +u8 acpi_ut_is_pci_root_bridge(char *id) +{ + + /* + * Check if this is a PCI root bridge. + * ACPI 3.0+: check for a PCI Express root also. + */ + if (!(ACPI_STRCMP(id, + PCI_ROOT_HID_STRING)) || + !(ACPI_STRCMP(id, PCI_EXPRESS_ROOT_HID_STRING))) { + return (TRUE); + } + + return (FALSE); +} + /******************************************************************************* * * FUNCTION: acpi_ut_is_aml_table diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index fe0cdf83641a..2aee8c24dc56 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -200,20 +200,17 @@ container_walk_namespace_cb(acpi_handle handle, u32 lvl, void *context, void **rv) { char *hid = NULL; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_device_info *info; acpi_status status; int *action = context; - - status = acpi_get_object_info(handle, &buffer); - if (ACPI_FAILURE(status) || !buffer.pointer) { + status = acpi_get_object_info(handle, &info); + if (ACPI_FAILURE(status)) { return AE_OK; } - info = buffer.pointer; if (info->valid & ACPI_VALID_HID) - hid = info->hardware_id.value; + hid = info->hardware_id.string; if (hid == NULL) { goto end; @@ -240,7 +237,7 @@ container_walk_namespace_cb(acpi_handle handle, } end: - kfree(buffer.pointer); + kfree(info); return AE_OK; } diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index efb959d6c8a9..39536b80bce7 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -231,18 +231,16 @@ static int is_ata(acpi_handle handle) static int is_battery(acpi_handle handle) { struct acpi_device_info *info; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; int ret = 1; - if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) + if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) return 0; - info = buffer.pointer; if (!(info->valid & ACPI_VALID_HID)) ret = 0; else - ret = !strcmp("PNP0C0A", info->hardware_id.value); + ret = !strcmp("PNP0C0A", info->hardware_id.string); - kfree(buffer.pointer); + kfree(info); return ret; } diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index a8a5c29958c8..27a7072347ea 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -93,15 +93,13 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; struct acpi_device_info *info; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_find_child *find = context; - status = acpi_get_object_info(handle, &buffer); + status = acpi_get_object_info(handle, &info); if (ACPI_SUCCESS(status)) { - info = buffer.pointer; if (info->address == find->address) find->handle = handle; - kfree(buffer.pointer); + kfree(info); } return AE_OK; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 781435d7e369..0ab526de7c55 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -60,13 +60,13 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, } if (acpi_dev->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list; + struct acpica_device_id_list *cid_list; int i; cid_list = acpi_dev->pnp.cid_list; for (i = 0; i < cid_list->count; i++) { count = snprintf(&modalias[len], size, "%s:", - cid_list->id[i].value); + cid_list->ids[i].string); if (count < 0 || count >= size) { printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size", acpi_dev->pnp.device_name, i); @@ -287,14 +287,14 @@ int acpi_match_device_ids(struct acpi_device *device, } if (device->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; + struct acpica_device_id_list *cid_list = device->pnp.cid_list; int i; for (id = ids; id->id[0]; id++) { /* compare multiple _CID entries against driver ids */ for (i = 0; i < cid_list->count; i++) { if (!strcmp((char*)id->id, - cid_list->id[i].value)) + cid_list->ids[i].string)) return 0; } } @@ -999,33 +999,89 @@ static int acpi_dock_match(struct acpi_device *device) return acpi_get_handle(device->handle, "_DCK", &tmp); } +static struct acpica_device_id_list* +acpi_add_cid( + struct acpi_device_info *info, + struct acpica_device_id *new_cid) +{ + struct acpica_device_id_list *cid; + char *next_id_string; + acpi_size cid_length; + acpi_size new_cid_length; + u32 i; + + + /* Allocate new CID list with room for the new CID */ + + if (!new_cid) + new_cid_length = info->compatible_id_list.list_size; + else if (info->compatible_id_list.list_size) + new_cid_length = info->compatible_id_list.list_size + + new_cid->length + sizeof(struct acpica_device_id); + else + new_cid_length = sizeof(struct acpica_device_id_list) + new_cid->length; + + cid = ACPI_ALLOCATE_ZEROED(new_cid_length); + if (!cid) { + return NULL; + } + + cid->list_size = new_cid_length; + cid->count = info->compatible_id_list.count; + if (new_cid) + cid->count++; + next_id_string = (char *) cid->ids + (cid->count * sizeof(struct acpica_device_id)); + + /* Copy all existing CIDs */ + + for (i = 0; i < info->compatible_id_list.count; i++) { + cid_length = info->compatible_id_list.ids[i].length; + cid->ids[i].string = next_id_string; + cid->ids[i].length = cid_length; + + ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string, + cid_length); + + next_id_string += cid_length; + } + + /* Append the new CID */ + + if (new_cid) { + cid->ids[i].string = next_id_string; + cid->ids[i].length = new_cid->length; + + ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length); + } + + return cid; +} + static void acpi_device_set_id(struct acpi_device *device, struct acpi_device *parent, acpi_handle handle, int type) { - struct acpi_device_info *info; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_device_info *info = NULL; char *hid = NULL; char *uid = NULL; - struct acpi_compatible_id_list *cid_list = NULL; - const char *cid_add = NULL; + struct acpica_device_id_list *cid_list = NULL; + char *cid_add = NULL; acpi_status status; switch (type) { case ACPI_BUS_TYPE_DEVICE: - status = acpi_get_object_info(handle, &buffer); + status = acpi_get_object_info(handle, &info); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); return; } - info = buffer.pointer; if (info->valid & ACPI_VALID_HID) - hid = info->hardware_id.value; + hid = info->hardware_id.string; if (info->valid & ACPI_VALID_UID) - uid = info->unique_id.value; + uid = info->unique_id.string; if (info->valid & ACPI_VALID_CID) - cid_list = &info->compatibility_id; + cid_list = &info->compatible_id_list; if (info->valid & ACPI_VALID_ADR) { device->pnp.bus_address = info->address; device->flags.bus_address = 1; @@ -1076,55 +1132,44 @@ static void acpi_device_set_id(struct acpi_device *device, } if (hid) { - strcpy(device->pnp.hardware_id, hid); - device->flags.hardware_id = 1; - } + device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1); + if (device->pnp.hardware_id) { + strcpy(device->pnp.hardware_id, hid); + device->flags.hardware_id = 1; + } + } else + device->pnp.hardware_id = NULL; + if (uid) { - strcpy(device->pnp.unique_id, uid); - device->flags.unique_id = 1; - } + device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); + if (device->pnp.unique_id) { + strcpy(device->pnp.unique_id, uid); + device->flags.unique_id = 1; + } + } else + device->pnp.unique_id = NULL; + if (cid_list || cid_add) { - struct acpi_compatible_id_list *list; - int size = 0; - int count = 0; - - if (cid_list) { - size = cid_list->size; - } else if (cid_add) { - size = sizeof(struct acpi_compatible_id_list); - cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size); - if (!cid_list) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(buffer.pointer); - return; - } else { - cid_list->count = 0; - cid_list->size = size; - } + struct acpica_device_id_list *list; + + if (cid_add) { + struct acpica_device_id cid; + cid.length = strlen (cid_add) + 1; + cid.string = cid_add; + + list = acpi_add_cid(info, &cid); + } else { + list = acpi_add_cid(info, NULL); } - if (cid_add) - size += sizeof(struct acpi_compatible_id); - list = kmalloc(size, GFP_KERNEL); if (list) { - if (cid_list) { - memcpy(list, cid_list, cid_list->size); - count = cid_list->count; - } - if (cid_add) { - strncpy(list->id[count].value, cid_add, - ACPI_MAX_CID_LENGTH); - count++; - device->flags.compatible_ids = 1; - } - list->size = size; - list->count = count; device->pnp.cid_list = list; - } else - printk(KERN_ERR PREFIX "Memory allocation error\n"); + if (cid_add) + device->flags.compatible_ids = 1; + } } - kfree(buffer.pointer); + kfree(info); } static int acpi_device_set_context(struct acpi_device *device, int type) diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 8f3d4c184914..7bead4c816ca 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -478,7 +478,6 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret) { acpi_handle handle, parent; acpi_status status; - struct acpi_buffer buffer; struct acpi_device_info *info; u64 lba_hpa, sba_hpa, length; int match; @@ -490,13 +489,11 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret) /* Look for an enclosing IOC scope and find its CSR space */ handle = obj; do { - buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_get_object_info(handle, &buffer); + status = acpi_get_object_info(handle, &info); if (ACPI_SUCCESS(status)) { /* TBD check _CID also */ - info = buffer.pointer; - info->hardware_id.value[sizeof(info->hardware_id)-1] = '\0'; - match = (strcmp(info->hardware_id.value, "HWP0001") == 0); + info->hardware_id.string[sizeof(info->hardware_id.length)-1] = '\0'; + match = (strcmp(info->hardware_id.string, "HWP0001") == 0); kfree(info); if (match) { status = hp_acpi_csr_space(handle, &sba_hpa, &length); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index c509c9916464..c0cf45a11b93 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -114,8 +114,6 @@ static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, unsigned int bus, devnum, func; acpi_integer addr; acpi_handle dev_handle; - struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, - .pointer = NULL}; acpi_status status; struct acpi_device_info *dinfo = NULL; int ret = -ENODEV; @@ -134,12 +132,11 @@ static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, goto err; } - status = acpi_get_object_info(dev_handle, &buffer); + status = acpi_get_object_info(dev_handle, &dinfo); if (ACPI_FAILURE(status)) { DEBPRINT("get_object_info for device failed\n"); goto err; } - dinfo = buffer.pointer; if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && dinfo->address == addr) { *pcidevfn = addr; diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index 5befa7e379b7..a9d926b7d805 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -398,23 +398,21 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle, acpi_handle *phandle = (acpi_handle *)context; acpi_status status; struct acpi_device_info *info; - struct acpi_buffer info_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; int retval = 0; - status = acpi_get_object_info(handle, &info_buffer); + status = acpi_get_object_info(handle, &info); if (ACPI_FAILURE(status)) { err("%s: Failed to get device information status=0x%x\n", __func__, status); return retval; } - info = info_buffer.pointer; - info->hardware_id.value[sizeof(info->hardware_id.value) - 1] = '\0'; + info->hardware_id.string[sizeof(info->hardware_id.length) - 1] = '\0'; if (info->current_status && (info->valid & ACPI_VALID_HID) && - (!strcmp(info->hardware_id.value, IBM_HARDWARE_ID1) || - !strcmp(info->hardware_id.value, IBM_HARDWARE_ID2))) { + (!strcmp(info->hardware_id.string, IBM_HARDWARE_ID1) || + !strcmp(info->hardware_id.string, IBM_HARDWARE_ID2))) { dbg("found hardware: %s, handle: %p\n", - info->hardware_id.value, handle); + info->hardware_id.string, handle); *phandle = handle; /* returning non-zero causes the search to stop * and returns this value to the caller of diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index dafaa4a92df5..f9f68e0e7344 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -976,15 +976,12 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, void *context, void **return_value) { struct acpi_device_info *info; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - - if (ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) { - info = buffer.pointer; + if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", (char *)&info->name, info->param_count); - kfree(buffer.pointer); + kfree(info); } return AE_OK; diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 9496494f340e..c07fdb94d665 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -194,13 +194,13 @@ static int __init pnpacpi_add_device(struct acpi_device *device) pnpacpi_parse_resource_option_data(dev); if (device->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; + struct acpica_device_id_list *cid_list = device->pnp.cid_list; int i; for (i = 0; i < cid_list->count; i++) { - if (!ispnpidacpi(cid_list->id[i].value)) + if (!ispnpidacpi(cid_list->ids[i].string)) continue; - pnp_add_id(dev, cid_list->id[i].value); + pnp_add_id(dev, cid_list->ids[i].string); } } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c65e4ce6c3af..b91420b52c6f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -173,17 +173,15 @@ struct acpi_device_dir { typedef char acpi_bus_id[8]; typedef unsigned long acpi_bus_address; -typedef char acpi_hardware_id[15]; -typedef char acpi_unique_id[9]; typedef char acpi_device_name[40]; typedef char acpi_device_class[20]; struct acpi_device_pnp { acpi_bus_id bus_id; /* Object name */ acpi_bus_address bus_address; /* _ADR */ - acpi_hardware_id hardware_id; /* _HID */ - struct acpi_compatible_id_list *cid_list; /* _CIDs */ - acpi_unique_id unique_id; /* _UID */ + char *hardware_id; /* _HID */ + struct acpica_device_id_list *cid_list; /* _CIDs */ + char *unique_id; /* _UID */ acpi_device_name device_name; /* Driver-determined */ acpi_device_class device_class; /* " */ }; diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index b450a195319a..04904c7f1aa1 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -200,7 +200,8 @@ acpi_evaluate_object_typed(acpi_handle object, acpi_object_type return_type); acpi_status -acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer); +acpi_get_object_info(acpi_handle handle, + struct acpi_device_info **return_buffer); acpi_status acpi_install_method(u8 *buffer); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 37ba576d06e8..7a4ff79e238c 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -338,7 +338,7 @@ typedef u32 acpi_physical_address; /* PM Timer ticks per second (HZ) */ -#define PM_TIMER_FREQUENCY 3579545 +#define PM_TIMER_FREQUENCY 3579545 /******************************************************************************* * @@ -969,38 +969,60 @@ acpi_status(*acpi_walk_callback) (acpi_handle obj_handle, #define ACPI_INTERRUPT_NOT_HANDLED 0x00 #define ACPI_INTERRUPT_HANDLED 0x01 -/* Length of _HID, _UID, _CID, and UUID values */ +/* Length of 32-bit EISAID values when converted back to a string */ + +#define ACPI_EISAID_STRING_SIZE 8 /* Includes null terminator */ + +/* Length of UUID (string) values */ -#define ACPI_DEVICE_ID_LENGTH 0x09 -#define ACPI_MAX_CID_LENGTH 48 #define ACPI_UUID_LENGTH 16 -/* Common string version of device HIDs and UIDs */ +/* Structures used for device/processor HID, UID, CID */ struct acpica_device_id { - char value[ACPI_DEVICE_ID_LENGTH]; + u32 length; /* Length of string + null */ + char *string; }; -/* Common string version of device CIDs */ - -struct acpi_compatible_id { - char value[ACPI_MAX_CID_LENGTH]; +struct acpica_device_id_list { + u32 count; /* Number of IDs in Ids array */ + u32 list_size; /* Size of list, including ID strings */ + struct acpica_device_id ids[1]; /* ID array */ }; -struct acpi_compatible_id_list { - u32 count; - u32 size; - struct acpi_compatible_id id[1]; +/* + * Structure returned from acpi_get_object_info. + * Optimized for both 32- and 64-bit builds + */ +struct acpi_device_info { + u32 info_size; /* Size of info, including ID strings */ + u32 name; /* ACPI object Name */ + acpi_object_type type; /* ACPI object Type */ + u8 param_count; /* If a method, required parameter count */ + u8 valid; /* Indicates which optional fields are valid */ + u8 flags; /* Miscellaneous info */ + u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ + u8 lowest_dstates[5]; /* _sx_w values: 0xFF indicates not valid */ + u32 current_status; /* _STA value */ + acpi_integer address; /* _ADR value */ + struct acpica_device_id hardware_id; /* _HID value */ + struct acpica_device_id unique_id; /* _UID value */ + struct acpica_device_id_list compatible_id_list; /* _CID list */ }; -/* Structure and flags for acpi_get_object_info */ +/* Values for Flags field above (acpi_get_object_info) */ + +#define ACPI_PCI_ROOT_BRIDGE 0x01 -#define ACPI_VALID_STA 0x0001 -#define ACPI_VALID_ADR 0x0002 -#define ACPI_VALID_HID 0x0004 -#define ACPI_VALID_UID 0x0008 -#define ACPI_VALID_CID 0x0010 -#define ACPI_VALID_SXDS 0x0020 +/* Flags for Valid field above (acpi_get_object_info) */ + +#define ACPI_VALID_STA 0x01 +#define ACPI_VALID_ADR 0x02 +#define ACPI_VALID_HID 0x04 +#define ACPI_VALID_UID 0x08 +#define ACPI_VALID_CID 0x10 +#define ACPI_VALID_SXDS 0x20 +#define ACPI_VALID_SXWS 0x40 /* Flags for _STA method */ @@ -1011,29 +1033,6 @@ struct acpi_compatible_id_list { #define ACPI_STA_DEVICE_OK 0x08 /* Synonym */ #define ACPI_STA_BATTERY_PRESENT 0x10 -#define ACPI_COMMON_OBJ_INFO \ - acpi_object_type type; /* ACPI object type */ \ - acpi_name name /* ACPI object Name */ - -struct acpi_obj_info_header { - ACPI_COMMON_OBJ_INFO; -}; - -/* Structure returned from Get Object Info */ - -struct acpi_device_info { - ACPI_COMMON_OBJ_INFO; - - u32 param_count; /* If a method, required parameter count */ - u32 valid; /* Indicates which fields below are valid */ - u32 current_status; /* _STA value */ - acpi_integer address; /* _ADR value if any */ - struct acpica_device_id hardware_id; /* _HID value if any */ - struct acpica_device_id unique_id; /* _UID value if any */ - u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ - struct acpi_compatible_id_list compatibility_id; /* List of _CIDs if any */ -}; - /* Context structs for address space handlers */ struct acpi_pci_id { -- cgit v1.2.3-59-g8ed1b From dbdc8f02fe8339686623c84745ba15b0f4f889a1 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 24 Jun 2009 11:22:22 +0800 Subject: ACPICA: Fix possible memory leak in nspredef Fixed a possible leak when an attempt is made to repair a return object. The only current repair is an automatic buffer to string conversion. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/nspredef.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 7f8e066b12a3..abbb855e1b9a 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -1046,22 +1046,25 @@ acpi_ns_repair_object(u32 expected_btypes, ACPI_MEMCPY(new_object->string.pointer, return_object->buffer.pointer, length); - /* Install the new return object */ - - acpi_ut_remove_reference(return_object); - *return_object_ptr = new_object; - /* - * If the object is a package element, we need to: - * 1. Decrement the reference count of the orignal object, it was - * incremented when building the package - * 2. Increment the reference count of the new object, it will be - * decremented when releasing the package + * If the original object is a package element, we need to: + * 1. Set the reference count of the new object to match the + * reference count of the old object. + * 2. Decrement the reference count of the original object. */ if (package_index != ACPI_NOT_PACKAGE) { - acpi_ut_remove_reference(return_object); - acpi_ut_add_reference(new_object); + new_object->common.reference_count = + return_object->common.reference_count; + + if (return_object->common.reference_count > 1) { + return_object->common.reference_count--; + } } + + /* Delete old object, install the new return object */ + + acpi_ut_remove_reference(return_object); + *return_object_ptr = new_object; return (AE_OK); default: -- cgit v1.2.3-59-g8ed1b From 3db20bed579bc4e7fe581c48ad1bde853aa9ff68 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Wed, 24 Jun 2009 11:25:17 +0800 Subject: ACPICA: ACPI 4.0: iASL/Disassembler - IPMI keyword support. Adds support for the new IPMI operation region keyword. ACPICA BZ 771, 772. http://acpica.org/bugzilla/show_bug.cgi?id=771 http://acpica.org/bugzilla/show_bug.cgi?id=772 Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/acpica/acconfig.h | 2 +- drivers/acpi/acpica/amlcode.h | 1 + drivers/acpi/acpica/utglobal.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index 6c1fb2d9f4d5..9123d5a11627 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -183,7 +183,7 @@ /* Operation regions */ -#define ACPI_NUM_PREDEFINED_REGIONS 8 +#define ACPI_NUM_PREDEFINED_REGIONS 9 #define ACPI_USER_REGION_BEGIN 0x80 /* Maximum space_ids for Operation Regions */ diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 067f967eb389..4940249f2524 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -404,6 +404,7 @@ typedef enum { REGION_SMBUS, REGION_CMOS, REGION_PCI_BAR, + REGION_IPMI, REGION_DATA_TABLE, /* Internal use only */ REGION_FIXED_HW = 0x7F } AML_REGION_TYPES; diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index ed7a33c67fbe..9e33b6261939 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -359,6 +359,7 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { "SMBus", "SystemCMOS", "PCIBARTarget", + "IPMI", "DataTable" }; -- cgit v1.2.3-59-g8ed1b From 6557a49a443a347d24aed58076365432ded30edc Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Wed, 24 Jun 2009 11:32:04 +0800 Subject: ACPICA: ACPI 4.0: Interpreter support for IPMI. Adds support for IPMI which is similar to SMBus and uses a bi-directional data buffer. ACPICA BZ 773. http://acpica.org/bugzilla/show_bug.cgi?id=773 Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/acpica/acconfig.h | 3 +- drivers/acpi/acpica/exfield.c | 82 ++++++++++++++++++++++++++++-------------- drivers/acpi/acpica/exfldio.c | 7 ++-- include/acpi/actypes.h | 3 +- 4 files changed, 63 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index 9123d5a11627..8e679ef5b231 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -199,9 +199,10 @@ #define ACPI_RSDP_CHECKSUM_LENGTH 20 #define ACPI_RSDP_XCHECKSUM_LENGTH 36 -/* SMBus bidirectional buffer size */ +/* SMBus and IPMI bidirectional buffer size */ #define ACPI_SMBUS_BUFFER_SIZE 34 +#define ACPI_IPMI_BUFFER_SIZE 66 /* _sx_d and _sx_w control methods */ diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 546dcdd86785..0b33d6c887b9 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -72,6 +72,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, union acpi_operand_object *buffer_desc; acpi_size length; void *buffer; + u32 function; ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); @@ -97,13 +98,27 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_SMBUS)) { + ACPI_ADR_SPACE_SMBUS + || obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_IPMI)) { /* - * This is an SMBus read. We must create a buffer to hold the data - * and directly access the region handler. + * This is an SMBus or IPMI read. We must create a buffer to hold + * the data and then directly access the region handler. + * + * Note: Smbus protocol value is passed in upper 16-bits of Function */ - buffer_desc = - acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE); + if (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_SMBUS) { + length = ACPI_SMBUS_BUFFER_SIZE; + function = + ACPI_READ | (obj_desc->field.attribute << 16); + } else { /* IPMI */ + + length = ACPI_IPMI_BUFFER_SIZE; + function = ACPI_READ; + } + + buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -112,16 +127,13 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); - /* - * Perform the read. - * Note: Smbus protocol value is passed in upper 16-bits of Function - */ + /* Call the region handler for the read */ + status = acpi_ex_access_region(obj_desc, 0, ACPI_CAST_PTR(acpi_integer, buffer_desc-> buffer.pointer), - ACPI_READ | (obj_desc->field. - attribute << 16)); + function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); goto exit; } @@ -212,6 +224,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, u32 length; void *buffer; union acpi_operand_object *buffer_desc; + u32 function; ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); @@ -234,39 +247,56 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_SMBUS)) { + ACPI_ADR_SPACE_SMBUS + || obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_IPMI)) { /* - * This is an SMBus write. We will bypass the entire field mechanism - * and handoff the buffer directly to the handler. + * This is an SMBus or IPMI write. We will bypass the entire field + * mechanism and handoff the buffer directly to the handler. For + * these address spaces, the buffer is bi-directional; on a write, + * return data is returned in the same buffer. + * + * Source must be a buffer of sufficient size: + * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE. * - * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE). + * Note: SMBus protocol type is passed in upper 16-bits of Function */ if (source_desc->common.type != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, - "SMBus write requires Buffer, found type %s", + "SMBus or IPMI write requires Buffer, found type %s", acpi_ut_get_object_type_name(source_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) { + if (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_SMBUS) { + length = ACPI_SMBUS_BUFFER_SIZE; + function = + ACPI_WRITE | (obj_desc->field.attribute << 16); + } else { /* IPMI */ + + length = ACPI_IPMI_BUFFER_SIZE; + function = ACPI_WRITE; + } + + if (source_desc->buffer.length < length) { ACPI_ERROR((AE_INFO, - "SMBus write requires Buffer of length %X, found length %X", - ACPI_SMBUS_BUFFER_SIZE, - source_desc->buffer.length)); + "SMBus or IPMI write requires Buffer of length %X, found length %X", + length, source_desc->buffer.length)); return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); } - buffer_desc = - acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE); + /* Create the bi-directional buffer */ + + buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; - ACPI_MEMCPY(buffer, source_desc->buffer.pointer, - ACPI_SMBUS_BUFFER_SIZE); + ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length); /* Lock entire transaction if requested */ @@ -275,12 +305,10 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, /* * Perform the write (returns status and perhaps data in the * same buffer) - * Note: SMBus protocol type is passed in upper 16-bits of Function. */ status = acpi_ex_access_region(obj_desc, 0, (acpi_integer *) buffer, - ACPI_WRITE | (obj_desc->field. - attribute << 16)); + function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); *result_desc = buffer_desc; diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 6687be167f5f..d7b3b418fb45 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -120,12 +120,13 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, } /* - * Exit now for SMBus address space, it has a non-linear address space + * Exit now for SMBus or IPMI address space, it has a non-linear address space * and the request cannot be directly validated */ - if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { + if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS || + rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) { - /* SMBus has a non-linear address space */ + /* SMBus or IPMI has a non-linear address space */ return_ACPI_STATUS(AE_OK); } diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 7a4ff79e238c..4371805d2def 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -732,7 +732,8 @@ typedef u8 acpi_adr_space_type; #define ACPI_ADR_SPACE_SMBUS (acpi_adr_space_type) 4 #define ACPI_ADR_SPACE_CMOS (acpi_adr_space_type) 5 #define ACPI_ADR_SPACE_PCI_BAR_TARGET (acpi_adr_space_type) 6 -#define ACPI_ADR_SPACE_DATA_TABLE (acpi_adr_space_type) 7 +#define ACPI_ADR_SPACE_IPMI (acpi_adr_space_type) 7 +#define ACPI_ADR_SPACE_DATA_TABLE (acpi_adr_space_type) 8 #define ACPI_ADR_SPACE_FIXED_HARDWARE (acpi_adr_space_type) 127 /* -- cgit v1.2.3-59-g8ed1b From 8e4319c425077c4cc540696a5bb6c4d12f017dcd Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 29 Jun 2009 13:43:27 +0800 Subject: ACPICA: Fix several acpi_attach_data problems Handler was never invoked. Now invoked if/when host node is deleted. Data object was not automatically deleted when host node was deleted. Interface to handler had an unused parameter, removed it. ACPICA BZ 778. http://acpica.org/bugzilla/show_bug.cgi?id=778 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acnamesp.h | 2 + drivers/acpi/acpica/nsalloc.c | 88 +++++++++++++++++++++++++++++------------- drivers/acpi/acpica/nsload.c | 3 +- drivers/acpi/bus.c | 2 +- drivers/acpi/glue.c | 2 +- drivers/acpi/scan.c | 2 +- include/acpi/acpi_bus.h | 4 +- include/acpi/actypes.h | 2 +- 8 files changed, 70 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 94cdc2b8cb93..a78e02f62d5e 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -144,6 +144,8 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name); void acpi_ns_delete_node(struct acpi_namespace_node *node); +void acpi_ns_remove_node(struct acpi_namespace_node *node); + void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_handle); diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index efc971ab7d65..8a58a1b85aa0 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -96,17 +96,68 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name) * * RETURN: None * - * DESCRIPTION: Delete a namespace node + * DESCRIPTION: Delete a namespace node. All node deletions must come through + * here. Detaches any attached objects, including any attached + * data. If a handler is associated with attached data, it is + * invoked before the node is deleted. * ******************************************************************************/ void acpi_ns_delete_node(struct acpi_namespace_node *node) +{ + union acpi_operand_object *obj_desc; + + ACPI_FUNCTION_NAME(ns_delete_node); + + /* Detach an object if there is one */ + + acpi_ns_detach_object(node); + + /* + * Delete an attached data object if present (an object that was created + * and attached via acpi_attach_data). Note: After any normal object is + * detached above, the only possible remaining object is a data object. + */ + obj_desc = node->object; + if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { + + /* Invoke the attached data deletion handler if present */ + + if (obj_desc->data.handler) { + obj_desc->data.handler(node, obj_desc->data.pointer); + } + + acpi_ut_remove_reference(obj_desc); + } + + /* Now we can delete the node */ + + (void)acpi_os_release_object(acpi_gbl_namespace_cache, node); + + ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); + ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n", + node, acpi_gbl_current_node_count)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_remove_node + * + * PARAMETERS: Node - Node to be removed/deleted + * + * RETURN: None + * + * DESCRIPTION: Remove (unlink) and delete a namespace node + * + ******************************************************************************/ + +void acpi_ns_remove_node(struct acpi_namespace_node *node) { struct acpi_namespace_node *parent_node; struct acpi_namespace_node *prev_node; struct acpi_namespace_node *next_node; - ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node); + ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node); parent_node = acpi_ns_get_parent_node(node); @@ -142,12 +193,9 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) } } - ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); - - /* Detach an object if there is one, then delete the node */ + /* Delete the node and any attached objects */ - acpi_ns_detach_object(node); - (void)acpi_os_release_object(acpi_gbl_namespace_cache, node); + acpi_ns_delete_node(node); return_VOID; } @@ -273,25 +321,11 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) parent_node, child_node)); } - /* Now we can free this child object */ - - ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); - - ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, - "Object %p, Remaining %X\n", child_node, - acpi_gbl_current_node_count)); - - /* Detach an object if there is one, then free the child node */ - - acpi_ns_detach_object(child_node); - - /* Now we can delete the node */ - - (void)acpi_os_release_object(acpi_gbl_namespace_cache, - child_node); - - /* And move on to the next child in the list */ - + /* + * Delete this child node and move on to the next child in the list. + * No need to unlink the node since we are deleting the entire branch. + */ + acpi_ns_delete_node(child_node); child_node = next_node; } while (!(flags & ANOBJ_END_OF_PEER_LIST)); @@ -433,7 +467,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) if (deletion_node) { acpi_ns_delete_children(deletion_node); - acpi_ns_delete_node(deletion_node); + acpi_ns_remove_node(deletion_node); deletion_node = NULL; } diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index dcd7a6adbbbc..a7234e60e985 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -270,8 +270,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) /* Now delete the starting object, and we are done */ - acpi_ns_delete_node(child_handle); - + acpi_ns_remove_node(child_handle); return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2876fc70c3a9..620183f13e5e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -141,7 +141,7 @@ int acpi_bus_get_status(struct acpi_device *device) EXPORT_SYMBOL(acpi_bus_get_status); void acpi_bus_private_data_handler(acpi_handle handle, - u32 function, void *context) + void *context) { return; } diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 27a7072347ea..9a4ce33f137e 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -119,7 +119,7 @@ EXPORT_SYMBOL(acpi_get_child); /* Link ACPI devices with physical devices */ static void acpi_glue_data_handler(acpi_handle handle, - u32 function, void *context) + void *context) { /* we provide an empty handler */ } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 0ab526de7c55..9606af13d3b8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -687,7 +687,7 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) } EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); -void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) +void acpi_bus_data_handler(acpi_handle handle, void *context) { /* TBD */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index b91420b52c6f..6e83a68fbd7b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -312,7 +312,7 @@ struct acpi_bus_event { extern struct kobject *acpi_kobj; extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); -void acpi_bus_private_data_handler(acpi_handle, u32, void *); +void acpi_bus_private_data_handler(acpi_handle, void *); int acpi_bus_get_private_data(acpi_handle, void **); extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); extern int register_acpi_notifier(struct notifier_block *); @@ -325,7 +325,7 @@ extern void unregister_acpi_bus_notifier(struct notifier_block *nb); */ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); -void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context); +void acpi_bus_data_handler(acpi_handle handle, void *context); int acpi_bus_get_status(struct acpi_device *device); int acpi_bus_get_power(acpi_handle handle, int *state); int acpi_bus_set_power(acpi_handle handle, int state); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 4371805d2def..ef4601149f49 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -922,7 +922,7 @@ typedef void (*acpi_notify_handler) (acpi_handle device, u32 value, void *context); typedef -void (*acpi_object_handler) (acpi_handle object, u32 function, void *data); +void (*acpi_object_handler) (acpi_handle object, void *data); typedef acpi_status(*acpi_init_handler) (acpi_handle object, u32 function); -- cgit v1.2.3-59-g8ed1b From cf02cd47d4747abf8ff0617e15fc05a00202e6d5 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 24 Jun 2009 11:38:46 +0800 Subject: ACPICA: Dump table header - suppress output of non-printable characters Function acpi_tb_print_table_header. Some ACPI tables contain non-printable characters in one of the string fields of the the header - Signature, OemId, OemTableId, or CompilerId. Invalid characters are replaced by '?'. ACPICA BZ 788. http://acpica.org/bugzilla/show_bug.cgi?id=788 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/tbutils.c | 82 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index ef7d2c2d8f0b..1f15497f00d1 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -49,6 +49,12 @@ ACPI_MODULE_NAME("tbutils") /* Local prototypes */ +static void acpi_tb_fix_string(char *string, acpi_size length); + +static void +acpi_tb_cleanup_table_header(struct acpi_table_header *out_header, + struct acpi_table_header *header); + static acpi_physical_address acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); @@ -159,6 +165,59 @@ u8 acpi_tb_tables_loaded(void) return (FALSE); } +/******************************************************************************* + * + * FUNCTION: acpi_tb_fix_string + * + * PARAMETERS: String - String to be repaired + * Length - Maximum length + * + * RETURN: None + * + * DESCRIPTION: Replace every non-printable or non-ascii byte in the string + * with a question mark '?'. + * + ******************************************************************************/ + +static void acpi_tb_fix_string(char *string, acpi_size length) +{ + + while (length && *string) { + if (!ACPI_IS_PRINT(*string)) { + *string = '?'; + } + string++; + length--; + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_cleanup_table_header + * + * PARAMETERS: out_header - Where the cleaned header is returned + * Header - Input ACPI table header + * + * RETURN: Returns the cleaned header in out_header + * + * DESCRIPTION: Copy the table header and ensure that all "string" fields in + * the header consist of printable characters. + * + ******************************************************************************/ + +static void +acpi_tb_cleanup_table_header(struct acpi_table_header *out_header, + struct acpi_table_header *header) +{ + + ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header)); + + acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE); + acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE); + acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE); + acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAME_SIZE); +} + /******************************************************************************* * * FUNCTION: acpi_tb_print_table_header @@ -176,6 +235,7 @@ void acpi_tb_print_table_header(acpi_physical_address address, struct acpi_table_header *header) { + struct acpi_table_header local_header; /* * The reason that the Address is cast to a void pointer is so that we @@ -192,6 +252,11 @@ acpi_tb_print_table_header(acpi_physical_address address, /* RSDP has no common fields */ + ACPI_MEMCPY(local_header.oem_id, + ACPI_CAST_PTR(struct acpi_table_rsdp, + header)->oem_id, ACPI_OEM_ID_SIZE); + acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE); + ACPI_INFO((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)", ACPI_CAST_PTR (void, address), (ACPI_CAST_PTR(struct acpi_table_rsdp, header)-> @@ -200,18 +265,21 @@ acpi_tb_print_table_header(acpi_physical_address address, header)->length : 20, ACPI_CAST_PTR(struct acpi_table_rsdp, header)->revision, - ACPI_CAST_PTR(struct acpi_table_rsdp, - header)->oem_id)); + local_header.oem_id)); } else { /* Standard ACPI table with full common header */ + acpi_tb_cleanup_table_header(&local_header, header); + ACPI_INFO((AE_INFO, "%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)", - header->signature, ACPI_CAST_PTR (void, address), - header->length, header->revision, header->oem_id, - header->oem_table_id, header->oem_revision, - header->asl_compiler_id, - header->asl_compiler_revision)); + local_header.signature, ACPI_CAST_PTR(void, address), + local_header.length, local_header.revision, + local_header.oem_id, local_header.oem_table_id, + local_header.oem_revision, + local_header.asl_compiler_id, + local_header.asl_compiler_revision)); + } } -- cgit v1.2.3-59-g8ed1b From 0444e8f6d72d6e38f92d48884bc90bbc6c22fd5a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 24 Jun 2009 13:38:02 +0800 Subject: ACPICA: Fix: Predefined object repair executed only once This fixes a problem where the code that attempts to repair/convert an object of incorrect type is only executed on the first time the predefined method is called. The mechanism that disables warnings on subsequent calls was interfering with the repair mechanism. ACPICA BZ 781. http://acpica.org/bugzilla/show_bug.cgi?id=781 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/aclocal.h | 13 ++ drivers/acpi/acpica/acmacros.h | 2 + drivers/acpi/acpica/acutils.h | 6 + drivers/acpi/acpica/nspredef.c | 369 +++++++++++++++++++++++------------------ drivers/acpi/acpica/utmisc.c | 57 ++++++- 5 files changed, 277 insertions(+), 170 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index ee986edfa0da..ff6689eba917 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -369,6 +369,19 @@ union acpi_predefined_info { struct acpi_package_info3 ret_info3; }; +/* Data block used during object validation */ + +struct acpi_predefined_data { + char *pathname; + const union acpi_predefined_info *predefined; + u32 flags; + u8 node_flags; +}; + +/* Defines for Flags field above */ + +#define ACPI_OBJECT_REPAIRED 1 + /* * Bitmapped return value types * Note: the actual data types must be contiguous, a loop in nspredef.c diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 91ac7d7b4402..3acd9c6760ea 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -340,6 +340,7 @@ */ #define ACPI_ERROR_NAMESPACE(s, e) acpi_ns_report_error (AE_INFO, s, e); #define ACPI_ERROR_METHOD(s, n, p, e) acpi_ns_report_method_error (AE_INFO, s, n, p, e); +#define ACPI_WARN_PREDEFINED(plist) acpi_ut_predefined_warning plist #else @@ -347,6 +348,7 @@ #define ACPI_ERROR_NAMESPACE(s, e) #define ACPI_ERROR_METHOD(s, n, p, e) +#define ACPI_WARN_PREDEFINED(plist) #endif /* ACPI_NO_ERROR_MESSAGES */ /* diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index b0add85de308..863a264b829e 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -475,6 +475,12 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position); acpi_status acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer); +void ACPI_INTERNAL_VAR_XFACE +acpi_ut_predefined_warning(const char *module_name, + u32 line_number, + char *pathname, + u8 node_flags, const char *format, ...); + /* Values for Base above (16=Hex, 10=Decimal) */ #define ACPI_ANY_BASE 0 diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index abbb855e1b9a..1dc1a4737aa9 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -72,31 +72,33 @@ ACPI_MODULE_NAME("nspredef") ******************************************************************************/ /* Local prototypes */ static acpi_status -acpi_ns_check_package(char *pathname, - union acpi_operand_object **return_object_ptr, - const union acpi_predefined_info *predefined); +acpi_ns_check_package(struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr); static acpi_status -acpi_ns_check_package_elements(char *pathname, +acpi_ns_check_package_elements(struct acpi_predefined_data *data, union acpi_operand_object **elements, u8 type1, u32 count1, u8 type2, u32 count2, u32 start_index); static acpi_status -acpi_ns_check_object_type(char *pathname, +acpi_ns_check_object_type(struct acpi_predefined_data *data, union acpi_operand_object **return_object_ptr, u32 expected_btypes, u32 package_index); static acpi_status -acpi_ns_check_reference(char *pathname, +acpi_ns_check_reference(struct acpi_predefined_data *data, union acpi_operand_object *return_object); static acpi_status -acpi_ns_repair_object(u32 expected_btypes, +acpi_ns_repair_object(struct acpi_predefined_data *data, + u32 expected_btypes, u32 package_index, union acpi_operand_object **return_object_ptr); +static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes); + /* * Names for the types that can be returned by the predefined objects. * Used for warning messages. Must be in the same order as the ACPI_RTYPEs @@ -109,13 +111,21 @@ static const char *acpi_rtype_names[] = { "/Reference", }; -#define ACPI_NOT_PACKAGE ACPI_UINT32_MAX +/* Object is not a package element */ + +#define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX + +/* Always emit warning message, not dependent on node flags */ + +#define ACPI_WARN_ALWAYS 0 /******************************************************************************* * * FUNCTION: acpi_ns_check_predefined_names * * PARAMETERS: Node - Namespace node for the method/object + * user_param_count - Number of parameters actually passed + * return_status - Status from the object evaluation * return_object_ptr - Pointer to the object returned from the * evaluation of a method or object * @@ -135,12 +145,13 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, acpi_status status = AE_OK; const union acpi_predefined_info *predefined; char *pathname; + struct acpi_predefined_data *data; /* Match the name for this method/object against the predefined list */ predefined = acpi_ns_check_for_predefined_name(node); - /* Get the full pathname to the object, for use in error messages */ + /* Get the full pathname to the object, for use in warning messages */ pathname = acpi_ns_get_external_pathname(node); if (!pathname) { @@ -158,28 +169,17 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, /* If not a predefined name, we cannot validate the return object */ if (!predefined) { - goto exit; - } - - /* If the method failed, we cannot validate the return object */ - - if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) { - goto exit; + goto cleanup; } /* - * Only validate the return value on the first successful evaluation of - * the method. This ensures that any warnings will only be emitted during - * the very first evaluation of the method/object. + * If the method failed or did not actually return an object, we cannot + * validate the return object */ - if (node->flags & ANOBJ_EVALUATED) { - goto exit; + if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) { + goto cleanup; } - /* Mark the node as having been successfully evaluated */ - - node->flags |= ANOBJ_EVALUATED; - /* * If there is no return value, check if we require a return value for * this predefined name. Either one return value is expected, or none, @@ -190,46 +190,63 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, if (!return_object) { if ((predefined->info.expected_btypes) && (!(predefined->info.expected_btypes & ACPI_RTYPE_NONE))) { - ACPI_ERROR((AE_INFO, - "%s: Missing expected return value", - pathname)); + ACPI_WARN_PREDEFINED((AE_INFO, pathname, + ACPI_WARN_ALWAYS, + "Missing expected return value")); status = AE_AML_NO_RETURN_VALUE; } - goto exit; + goto cleanup; } /* * We have a return value, but if one wasn't expected, just exit, this is - * not a problem - * - * For example, if the "Implicit Return" feature is enabled, methods will - * always return a value + * not a problem. For example, if the "Implicit Return" feature is + * enabled, methods will always return a value. */ if (!predefined->info.expected_btypes) { - goto exit; + goto cleanup; + } + + /* Create the parameter data block for object validation */ + + data = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_predefined_data)); + if (!data) { + goto cleanup; } + data->predefined = predefined; + data->node_flags = node->flags; + data->pathname = pathname; /* * Check that the type of the return object is what is expected for * this predefined name */ - status = acpi_ns_check_object_type(pathname, return_object_ptr, + status = acpi_ns_check_object_type(data, return_object_ptr, predefined->info.expected_btypes, - ACPI_NOT_PACKAGE); + ACPI_NOT_PACKAGE_ELEMENT); if (ACPI_FAILURE(status)) { - goto exit; + goto check_validation_status; } /* For returned Package objects, check the type of all sub-objects */ if (return_object->common.type == ACPI_TYPE_PACKAGE) { - status = - acpi_ns_check_package(pathname, return_object_ptr, - predefined); + status = acpi_ns_check_package(data, return_object_ptr); } - exit: +check_validation_status: + /* + * If the object validation failed or if we successfully repaired one + * or more objects, mark the parent node to suppress further warning + * messages during the next evaluation of the same method/object. + */ + if (ACPI_FAILURE(status) || (data->flags & ACPI_OBJECT_REPAIRED)) { + node->flags |= ANOBJ_EVALUATED; + } + ACPI_FREE(data); + +cleanup: ACPI_FREE(pathname); return (status); } @@ -268,64 +285,58 @@ acpi_ns_check_parameter_count(char *pathname, param_count = node->object->method.param_count; } - /* Argument count check for non-predefined methods/objects */ - if (!predefined) { /* + * Check the parameter count for non-predefined methods/objects. + * * Warning if too few or too many arguments have been passed by the * caller. An incorrect number of arguments may not cause the method * to fail. However, the method will fail if there are too few * arguments and the method attempts to use one of the missing ones. */ if (user_param_count < param_count) { - ACPI_WARNING((AE_INFO, - "%s: Insufficient arguments - needs %d, found %d", - pathname, param_count, user_param_count)); + ACPI_WARN_PREDEFINED((AE_INFO, pathname, + ACPI_WARN_ALWAYS, + "Insufficient arguments - needs %u, found %u", + param_count, user_param_count)); } else if (user_param_count > param_count) { - ACPI_WARNING((AE_INFO, - "%s: Excess arguments - needs %d, found %d", - pathname, param_count, user_param_count)); + ACPI_WARN_PREDEFINED((AE_INFO, pathname, + ACPI_WARN_ALWAYS, + "Excess arguments - needs %u, found %u", + param_count, user_param_count)); } return; } - /* Allow two different legal argument counts (_SCP, etc.) */ - + /* + * Validate the user-supplied parameter count. + * Allow two different legal argument counts (_SCP, etc.) + */ required_params_current = predefined->info.param_count & 0x0F; required_params_old = predefined->info.param_count >> 4; if (user_param_count != ACPI_UINT32_MAX) { - - /* Validate the user-supplied parameter count */ - if ((user_param_count != required_params_current) && (user_param_count != required_params_old)) { - ACPI_WARNING((AE_INFO, - "%s: Parameter count mismatch - " - "caller passed %d, ACPI requires %d", - pathname, user_param_count, - required_params_current)); + ACPI_WARN_PREDEFINED((AE_INFO, pathname, + ACPI_WARN_ALWAYS, + "Parameter count mismatch - " + "caller passed %u, ACPI requires %u", + user_param_count, + required_params_current)); } } - /* - * Only validate the argument count on the first successful evaluation of - * the method. This ensures that any warnings will only be emitted during - * the very first evaluation of the method/object. - */ - if (node->flags & ANOBJ_EVALUATED) { - return; - } - /* * Check that the ASL-defined parameter count is what is expected for - * this predefined name. + * this predefined name (parameter count as defined by the ACPI + * specification) */ if ((param_count != required_params_current) && (param_count != required_params_old)) { - ACPI_WARNING((AE_INFO, - "%s: Parameter count mismatch - ASL declared %d, ACPI requires %d", - pathname, param_count, required_params_current)); + ACPI_WARN_PREDEFINED((AE_INFO, pathname, node->flags, + "Parameter count mismatch - ASL declared %u, ACPI requires %u", + param_count, required_params_current)); } } @@ -358,9 +369,6 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct this_name = predefined_names; while (this_name->info.name[0]) { if (ACPI_COMPARE_NAME(node->name.ascii, this_name->info.name)) { - - /* Return pointer to this table entry */ - return (this_name); } @@ -375,17 +383,16 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct this_name++; } - return (NULL); + return (NULL); /* Not found */ } /******************************************************************************* * * FUNCTION: acpi_ns_check_package * - * PARAMETERS: Pathname - Full pathname to the node (for error msgs) + * PARAMETERS: Data - Pointer to validation data structure * return_object_ptr - Pointer to the object returned from the * evaluation of a method or object - * Predefined - Pointer to entry in predefined name table * * RETURN: Status * @@ -395,9 +402,8 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct ******************************************************************************/ static acpi_status -acpi_ns_check_package(char *pathname, - union acpi_operand_object **return_object_ptr, - const union acpi_predefined_info *predefined) +acpi_ns_check_package(struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr) { union acpi_operand_object *return_object = *return_object_ptr; const union acpi_predefined_info *package; @@ -414,11 +420,11 @@ acpi_ns_check_package(char *pathname, /* The package info for this name is in the next table entry */ - package = predefined + 1; + package = data->predefined + 1; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s Validating return Package of Type %X, Count %X\n", - pathname, package->ret_info.type, + data->pathname, package->ret_info.type, return_object->package.count)); /* Extract package count and elements array */ @@ -429,9 +435,8 @@ acpi_ns_check_package(char *pathname, /* The package must have at least one element, else invalid */ if (!count) { - ACPI_WARNING((AE_INFO, - "%s: Return Package has no elements (empty)", - pathname)); + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Return Package has no elements (empty)")); return (AE_AML_OPERAND_VALUE); } @@ -456,15 +461,16 @@ acpi_ns_check_package(char *pathname, if (count < expected_count) { goto package_too_small; } else if (count > expected_count) { - ACPI_WARNING((AE_INFO, - "%s: Return Package is larger than needed - " - "found %u, expected %u", pathname, count, - expected_count)); + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, + data->node_flags, + "Return Package is larger than needed - " + "found %u, expected %u", count, + expected_count)); } /* Validate all elements of the returned package */ - status = acpi_ns_check_package_elements(pathname, elements, + status = acpi_ns_check_package_elements(data, elements, package->ret_info. object_type1, package->ret_info. @@ -485,7 +491,7 @@ acpi_ns_check_package(char *pathname, * elements must be of the same type */ for (i = 0; i < count; i++) { - status = acpi_ns_check_object_type(pathname, elements, + status = acpi_ns_check_object_type(data, elements, package->ret_info. object_type1, i); if (ACPI_FAILURE(status)) { @@ -517,8 +523,7 @@ acpi_ns_check_package(char *pathname, /* These are the required package elements (0, 1, or 2) */ status = - acpi_ns_check_object_type(pathname, - elements, + acpi_ns_check_object_type(data, elements, package-> ret_info3. object_type[i], @@ -530,8 +535,7 @@ acpi_ns_check_package(char *pathname, /* These are the optional package elements */ status = - acpi_ns_check_object_type(pathname, - elements, + acpi_ns_check_object_type(data, elements, package-> ret_info3. tail_object_type, @@ -548,7 +552,7 @@ acpi_ns_check_package(char *pathname, /* First element is the (Integer) count of sub-packages to follow */ - status = acpi_ns_check_object_type(pathname, elements, + status = acpi_ns_check_object_type(data, elements, ACPI_RTYPE_INTEGER, 0); if (ACPI_FAILURE(status)) { return (status); @@ -585,9 +589,9 @@ acpi_ns_check_package(char *pathname, /* Each sub-object must be of type Package */ - status = - acpi_ns_check_object_type(pathname, &sub_package, - ACPI_RTYPE_PACKAGE, i); + status = acpi_ns_check_object_type(data, &sub_package, + ACPI_RTYPE_PACKAGE, + i); if (ACPI_FAILURE(status)) { return (status); } @@ -610,7 +614,7 @@ acpi_ns_check_package(char *pathname, } status = - acpi_ns_check_package_elements(pathname, + acpi_ns_check_package_elements(data, sub_elements, package-> ret_info. @@ -643,7 +647,7 @@ acpi_ns_check_package(char *pathname, for (j = 0; j < expected_count; j++) { status = - acpi_ns_check_object_type(pathname, + acpi_ns_check_object_type(data, &sub_elements[j], package->ret_info2.object_type[j], j); if (ACPI_FAILURE(status)) { @@ -665,7 +669,7 @@ acpi_ns_check_package(char *pathname, /* Check the type of each sub-package element */ status = - acpi_ns_check_package_elements(pathname, + acpi_ns_check_package_elements(data, sub_elements, package-> ret_info. @@ -684,7 +688,7 @@ acpi_ns_check_package(char *pathname, /* First element is the (Integer) count of elements to follow */ status = - acpi_ns_check_object_type(pathname, + acpi_ns_check_object_type(data, sub_elements, ACPI_RTYPE_INTEGER, 0); @@ -704,7 +708,7 @@ acpi_ns_check_package(char *pathname, /* Check the type of each sub-package element */ status = - acpi_ns_check_package_elements(pathname, + acpi_ns_check_package_elements(data, (sub_elements + 1), package-> @@ -730,9 +734,9 @@ acpi_ns_check_package(char *pathname, /* Should not get here if predefined info table is correct */ - ACPI_WARNING((AE_INFO, - "%s: Invalid internal return type in table entry: %X", - pathname, package->ret_info.type)); + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Invalid internal return type in table entry: %X", + package->ret_info.type)); return (AE_AML_INTERNAL); } @@ -743,9 +747,9 @@ acpi_ns_check_package(char *pathname, /* Error exit for the case with an incorrect package count */ - ACPI_WARNING((AE_INFO, "%s: Return Package is too small - " - "found %u, expected %u", pathname, count, - expected_count)); + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Return Package is too small - found %u, expected %u", + count, expected_count)); return (AE_AML_OPERAND_VALUE); } @@ -754,7 +758,7 @@ acpi_ns_check_package(char *pathname, * * FUNCTION: acpi_ns_check_package_elements * - * PARAMETERS: Pathname - Full pathname to the node (for error msgs) + * PARAMETERS: Data - Pointer to validation data structure * Elements - Pointer to the package elements array * Type1 - Object type for first group * Count1 - Count for first group @@ -770,7 +774,7 @@ acpi_ns_check_package(char *pathname, ******************************************************************************/ static acpi_status -acpi_ns_check_package_elements(char *pathname, +acpi_ns_check_package_elements(struct acpi_predefined_data *data, union acpi_operand_object **elements, u8 type1, u32 count1, @@ -786,7 +790,7 @@ acpi_ns_check_package_elements(char *pathname, * The second group can have a count of zero. */ for (i = 0; i < count1; i++) { - status = acpi_ns_check_object_type(pathname, this_element, + status = acpi_ns_check_object_type(data, this_element, type1, i + start_index); if (ACPI_FAILURE(status)) { return (status); @@ -795,7 +799,7 @@ acpi_ns_check_package_elements(char *pathname, } for (i = 0; i < count2; i++) { - status = acpi_ns_check_object_type(pathname, this_element, + status = acpi_ns_check_object_type(data, this_element, type2, (i + count1 + start_index)); if (ACPI_FAILURE(status)) { @@ -811,12 +815,13 @@ acpi_ns_check_package_elements(char *pathname, * * FUNCTION: acpi_ns_check_object_type * - * PARAMETERS: Pathname - Full pathname to the node (for error msgs) + * PARAMETERS: Data - Pointer to validation data structure * return_object_ptr - Pointer to the object returned from the * evaluation of a method or object * expected_btypes - Bitmap of expected return type(s) * package_index - Index of object within parent package (if - * applicable - ACPI_NOT_PACKAGE otherwise) + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) * * RETURN: Status * @@ -826,7 +831,7 @@ acpi_ns_check_package_elements(char *pathname, ******************************************************************************/ static acpi_status -acpi_ns_check_object_type(char *pathname, +acpi_ns_check_object_type(struct acpi_predefined_data *data, union acpi_operand_object **return_object_ptr, u32 expected_btypes, u32 package_index) { @@ -834,9 +839,6 @@ acpi_ns_check_object_type(char *pathname, acpi_status status = AE_OK; u32 return_btype; char type_buffer[48]; /* Room for 5 types */ - u32 this_rtype; - u32 i; - u32 j; /* * If we get a NULL return_object here, it is a NULL package element, @@ -849,10 +851,11 @@ acpi_ns_check_object_type(char *pathname, /* A Namespace node should not get here, but make sure */ if (ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) { - ACPI_WARNING((AE_INFO, - "%s: Invalid return type - Found a Namespace node [%4.4s] type %s", - pathname, return_object->node.name.ascii, - acpi_ut_get_type_name(return_object->node.type))); + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Invalid return type - Found a Namespace node [%4.4s] type %s", + return_object->node.name.ascii, + acpi_ut_get_type_name(return_object->node. + type))); return (AE_AML_OPERAND_TYPE); } @@ -897,10 +900,11 @@ acpi_ns_check_object_type(char *pathname, /* Type mismatch -- attempt repair of the returned object */ - status = acpi_ns_repair_object(expected_btypes, package_index, + status = acpi_ns_repair_object(data, expected_btypes, + package_index, return_object_ptr); if (ACPI_SUCCESS(status)) { - return (status); + return (AE_OK); /* Repair was successful */ } goto type_error_exit; } @@ -908,7 +912,7 @@ acpi_ns_check_object_type(char *pathname, /* For reference objects, check that the reference type is correct */ if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) { - status = acpi_ns_check_reference(pathname, return_object); + status = acpi_ns_check_reference(data, return_object); } return (status); @@ -917,33 +921,19 @@ acpi_ns_check_object_type(char *pathname, /* Create a string with all expected types for this predefined object */ - j = 1; - type_buffer[0] = 0; - this_rtype = ACPI_RTYPE_INTEGER; - - for (i = 0; i < ACPI_NUM_RTYPES; i++) { - - /* If one of the expected types, concatenate the name of this type */ - - if (expected_btypes & this_rtype) { - ACPI_STRCAT(type_buffer, &acpi_rtype_names[i][j]); - j = 0; /* Use name separator from now on */ - } - this_rtype <<= 1; /* Next Rtype */ - } + acpi_ns_get_expected_types(type_buffer, expected_btypes); - if (package_index == ACPI_NOT_PACKAGE) { - ACPI_WARNING((AE_INFO, - "%s: Return type mismatch - found %s, expected %s", - pathname, - acpi_ut_get_object_type_name(return_object), - type_buffer)); + if (package_index == ACPI_NOT_PACKAGE_ELEMENT) { + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Return type mismatch - found %s, expected %s", + acpi_ut_get_object_type_name + (return_object), type_buffer)); } else { - ACPI_WARNING((AE_INFO, - "%s: Return Package type mismatch at index %u - " - "found %s, expected %s", pathname, package_index, - acpi_ut_get_object_type_name(return_object), - type_buffer)); + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Return Package type mismatch at index %u - " + "found %s, expected %s", package_index, + acpi_ut_get_object_type_name + (return_object), type_buffer)); } return (AE_AML_OPERAND_TYPE); @@ -953,7 +943,7 @@ acpi_ns_check_object_type(char *pathname, * * FUNCTION: acpi_ns_check_reference * - * PARAMETERS: Pathname - Full pathname to the node (for error msgs) + * PARAMETERS: Data - Pointer to validation data structure * return_object - Object returned from the evaluation of a * method or object * @@ -966,7 +956,7 @@ acpi_ns_check_object_type(char *pathname, ******************************************************************************/ static acpi_status -acpi_ns_check_reference(char *pathname, +acpi_ns_check_reference(struct acpi_predefined_data *data, union acpi_operand_object *return_object) { @@ -979,11 +969,10 @@ acpi_ns_check_reference(char *pathname, return (AE_OK); } - ACPI_WARNING((AE_INFO, - "%s: Return type mismatch - " - "unexpected reference object type [%s] %2.2X", - pathname, acpi_ut_get_reference_name(return_object), - return_object->reference.class)); + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Return type mismatch - unexpected reference object type [%s] %2.2X", + acpi_ut_get_reference_name(return_object), + return_object->reference.class)); return (AE_AML_OPERAND_TYPE); } @@ -992,8 +981,11 @@ acpi_ns_check_reference(char *pathname, * * FUNCTION: acpi_ns_repair_object * - * PARAMETERS: Pathname - Full pathname to the node (for error msgs) - * package_index - Used to determine if target is in a package + * PARAMETERS: Data - Pointer to validation data structure + * expected_btypes - Object types expected + * package_index - Index of object within parent package (if + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) * return_object_ptr - Pointer to the object returned from the * evaluation of a method or object * @@ -1005,7 +997,8 @@ acpi_ns_check_reference(char *pathname, ******************************************************************************/ static acpi_status -acpi_ns_repair_object(u32 expected_btypes, +acpi_ns_repair_object(struct acpi_predefined_data *data, + u32 expected_btypes, u32 package_index, union acpi_operand_object **return_object_ptr) { @@ -1016,6 +1009,8 @@ acpi_ns_repair_object(u32 expected_btypes, switch (return_object->common.type) { case ACPI_TYPE_BUFFER: + /* Does the method/object legally return a string? */ + if (!(expected_btypes & ACPI_RTYPE_STRING)) { return (AE_AML_OPERAND_TYPE); } @@ -1052,19 +1047,29 @@ acpi_ns_repair_object(u32 expected_btypes, * reference count of the old object. * 2. Decrement the reference count of the original object. */ - if (package_index != ACPI_NOT_PACKAGE) { + if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { new_object->common.reference_count = return_object->common.reference_count; if (return_object->common.reference_count > 1) { return_object->common.reference_count--; } + + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, + data->node_flags, + "Converted Buffer to expected String at index %u", + package_index)); + } else { + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, + data->node_flags, + "Converted Buffer to expected String")); } /* Delete old object, install the new return object */ acpi_ut_remove_reference(return_object); *return_object_ptr = new_object; + data->flags |= ACPI_OBJECT_REPAIRED; return (AE_OK); default: @@ -1073,3 +1078,39 @@ acpi_ns_repair_object(u32 expected_btypes, return (AE_AML_OPERAND_TYPE); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_expected_types + * + * PARAMETERS: Buffer - Pointer to where the string is returned + * expected_btypes - Bitmap of expected return type(s) + * + * RETURN: Buffer is populated with type names. + * + * DESCRIPTION: Translate the expected types bitmap into a string of ascii + * names of expected types, for use in warning messages. + * + ******************************************************************************/ + +static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes) +{ + u32 this_rtype; + u32 i; + u32 j; + + j = 1; + buffer[0] = 0; + this_rtype = ACPI_RTYPE_INTEGER; + + for (i = 0; i < ACPI_NUM_RTYPES; i++) { + + /* If one of the expected types, concatenate the name of this type */ + + if (expected_btypes & this_rtype) { + ACPI_STRCAT(buffer, &acpi_rtype_names[i][j]); + j = 0; /* Use name separator from now on */ + } + this_rtype <<= 1; /* Next Rtype */ + } +} diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 9cd65334ca75..5bd29606dc61 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -50,6 +50,11 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmisc") +/* + * Common suffix for messages + */ +#define ACPI_COMMON_MSG_SUFFIX \ + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, line_number) /******************************************************************************* * * FUNCTION: acpi_ut_validate_exception @@ -1065,8 +1070,7 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...) va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, - line_number); + ACPI_COMMON_MSG_SUFFIX; va_end(args); } @@ -1080,8 +1084,7 @@ acpi_exception(const char *module_name, va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, - line_number); + ACPI_COMMON_MSG_SUFFIX; va_end(args); } @@ -1094,8 +1097,7 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...) va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, - line_number); + ACPI_COMMON_MSG_SUFFIX; va_end(args); } @@ -1116,3 +1118,46 @@ ACPI_EXPORT_SYMBOL(acpi_error) ACPI_EXPORT_SYMBOL(acpi_exception) ACPI_EXPORT_SYMBOL(acpi_warning) ACPI_EXPORT_SYMBOL(acpi_info) + +/******************************************************************************* + * + * FUNCTION: acpi_ut_predefined_warning + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * Pathname - Full pathname to the node + * node_flags - From Namespace node for the method/object + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Warnings for the predefined validation module. Messages are + * only emitted the first time a problem with a particular + * method/object is detected. This prevents a flood of error + * messages for methods that are repeatedly evaluated. + * +******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +acpi_ut_predefined_warning(const char *module_name, + u32 line_number, + char *pathname, + u8 node_flags, const char *format, ...) +{ + va_list args; + + /* + * Warning messages for this method/object will be disabled after the + * first time a validation fails or an object is successfully repaired. + */ + if (node_flags & ANOBJ_EVALUATED) { + return; + } + + acpi_os_printf("ACPI Warning for %s: ", pathname); + + va_start(args, format); + acpi_os_vprintf(format, args); + ACPI_COMMON_MSG_SUFFIX; + va_end(args); +} -- cgit v1.2.3-59-g8ed1b From 8d590c7af1152685efcf302905baeb6dda3c2d2f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 24 Jun 2009 13:39:29 +0800 Subject: ACPICA: Clarify common suffix for error/warning messages Added parens around the acpica version/modulename/linenumber to clearly differentiate this group from the rest of the message. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/utmisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 5bd29606dc61..61f6315fce9f 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -54,7 +54,7 @@ ACPI_MODULE_NAME("utmisc") * Common suffix for messages */ #define ACPI_COMMON_MSG_SUFFIX \ - acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, line_number) + acpi_os_printf(" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number) /******************************************************************************* * * FUNCTION: acpi_ut_validate_exception -- cgit v1.2.3-59-g8ed1b From a5fe1a03f7720b8da8364a1737e1e5a357904e99 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Thu, 13 Aug 2009 10:43:27 +0800 Subject: ACPICA: fix leak of acpi_os_validate_address http://bugzilla.kernel.org/show_bug.cgi?id=13620 If the dynamic region is created and added to resource list over and over again, it has the potential to be a memory leak by growing the list every time. This patch fixes the memory leak, as below 1) add a new field "count" to struct acpi_res_list. When inserting, if the region(addr, len) is already in the resource list, we just increase "count", otherwise, the region is inserted with count=1. When deleting, the "count" is decreased, if it's decreased to 0, the region is deleted from the resource list. With "count", the region with same address and length can only be inserted to the resource list once, so prevent potential memory leak. 2) add a new function acpi_os_invalidate_address, which is called when region is deleted. Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/utdelete.c | 6 +++ drivers/acpi/osl.c | 94 ++++++++++++++++++++++++++++++++++++++++-- include/acpi/acpiosxf.h | 3 ++ 3 files changed, 100 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index bc1710315088..96e26e70c63d 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -215,6 +215,12 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object)); + /* Invalidate the region address/length via the host OS */ + + acpi_os_invalidate_address(object->region.space_id, + object->region.address, + (acpi_size) object->region.length); + second_desc = acpi_ns_get_secondary_object(object); if (second_desc) { /* diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 5691f165a952..c5b4f1ed9b71 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -88,6 +88,7 @@ struct acpi_res_list { char name[5]; /* only can have a length of 4 chars, make use of this one instead of res->name, no need to kalloc then */ struct list_head resource_list; + int count; }; static LIST_HEAD(resource_list_head); @@ -1358,6 +1359,89 @@ acpi_os_validate_interface (char *interface) return AE_SUPPORT; } +static inline int acpi_res_list_add(struct acpi_res_list *res) +{ + struct acpi_res_list *res_list_elem; + + list_for_each_entry(res_list_elem, &resource_list_head, + resource_list) { + + if (res->resource_type == res_list_elem->resource_type && + res->start == res_list_elem->start && + res->end == res_list_elem->end) { + + /* + * The Region(addr,len) already exist in the list, + * just increase the count + */ + + res_list_elem->count++; + return 0; + } + } + + res->count = 1; + list_add(&res->resource_list, &resource_list_head); + return 1; +} + +static inline void acpi_res_list_del(struct acpi_res_list *res) +{ + struct acpi_res_list *res_list_elem; + + list_for_each_entry(res_list_elem, &resource_list_head, + resource_list) { + + if (res->resource_type == res_list_elem->resource_type && + res->start == res_list_elem->start && + res->end == res_list_elem->end) { + + /* + * If the res count is decreased to 0, + * remove and free it + */ + + if (--res_list_elem->count == 0) { + list_del(&res_list_elem->resource_list); + kfree(res_list_elem); + } + return; + } + } +} + +acpi_status +acpi_os_invalidate_address( + u8 space_id, + acpi_physical_address address, + acpi_size length) +{ + struct acpi_res_list res; + + switch (space_id) { + case ACPI_ADR_SPACE_SYSTEM_IO: + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + /* Only interference checks against SystemIO and SytemMemory + are needed */ + res.start = address; + res.end = address + length - 1; + res.resource_type = space_id; + spin_lock(&acpi_res_lock); + acpi_res_list_del(&res); + spin_unlock(&acpi_res_lock); + break; + case ACPI_ADR_SPACE_PCI_CONFIG: + case ACPI_ADR_SPACE_EC: + case ACPI_ADR_SPACE_SMBUS: + case ACPI_ADR_SPACE_CMOS: + case ACPI_ADR_SPACE_PCI_BAR_TARGET: + case ACPI_ADR_SPACE_DATA_TABLE: + case ACPI_ADR_SPACE_FIXED_HARDWARE: + break; + } + return AE_OK; +} + /****************************************************************************** * * FUNCTION: acpi_os_validate_address @@ -1382,6 +1466,7 @@ acpi_os_validate_address ( char *name) { struct acpi_res_list *res; + int added; if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) return AE_OK; @@ -1399,14 +1484,17 @@ acpi_os_validate_address ( res->end = address + length - 1; res->resource_type = space_id; spin_lock(&acpi_res_lock); - list_add(&res->resource_list, &resource_list_head); + added = acpi_res_list_add(res); spin_unlock(&acpi_res_lock); - pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, " - "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO) + pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " + "name: %s\n", added ? "Added" : "Already exist", + (space_id == ACPI_ADR_SPACE_SYSTEM_IO) ? "SystemIO" : "System Memory", (unsigned long long)res->start, (unsigned long long)res->end, res->name); + if (!added) + kfree(res); break; case ACPI_ADR_SPACE_PCI_CONFIG: case ACPI_ADR_SPACE_EC: diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index ab0b85cf21f3..eb0e7189075f 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -245,6 +245,9 @@ acpi_status acpi_osi_invalidate(char* interface); acpi_status acpi_os_validate_address(u8 space_id, acpi_physical_address address, acpi_size length, char *name); +acpi_status +acpi_os_invalidate_address(u8 space_id, acpi_physical_address address, + acpi_size length); u64 acpi_os_get_timer(void); -- cgit v1.2.3-59-g8ed1b From 3b5e634103a5471d74e55d774e53db3df5c7b650 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 6 Aug 2009 15:57:54 -0700 Subject: ACPI: video: remove unneeded memsets device->cap and video->cap are zeroed initially so we don't need to clear them again. Signed-off-by: Zhang Rui Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/video.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 8851315ce858..a0cd0c7ee9e2 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -934,9 +934,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) { acpi_handle h_dummy1; - - memset(&device->cap, 0, sizeof(device->cap)); - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) { device->cap._ADR = 1; } @@ -1039,7 +1036,6 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video) { acpi_handle h_dummy1; - memset(&video->cap, 0, sizeof(video->cap)); if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) { video->cap._DOS = 1; } -- cgit v1.2.3-59-g8ed1b From c1b5310a957c47d1c66bb53035c6ba6aa20a150f Mon Sep 17 00:00:00 2001 From: Jonathan Woithe Date: Thu, 27 Aug 2009 18:45:33 -0400 Subject: fujitsu-laptop: fix config corner case This patch is a trivial fix for a config corner case, ensuring that fujitsu-laptop doesn't get compiled into the kernel when the led class is a module. Signed-off-by: Alan Jenkins Signed-off-by: Jonathan Woithe Signed-off-by: Len Brown --- drivers/platform/x86/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 77c6097ced80..0b5a85b8048f 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -99,6 +99,7 @@ config FUJITSU_LAPTOP depends on ACPI depends on INPUT depends on BACKLIGHT_CLASS_DEVICE + depends on LEDS_CLASS || LEDS_CLASS=n ---help--- This is a driver for laptops built by Fujitsu: -- cgit v1.2.3-59-g8ed1b From 1e384cb0f9a940f2a431d1708f963987e61d71e3 Mon Sep 17 00:00:00 2001 From: Stephen Gildea Date: Tue, 25 Aug 2009 14:41:52 +0930 Subject: fujitsu-laptop: support led-class as module Support fujitsu-laptop with led-class built as a module instead of being compiled in. Signed-off-by: Stephen Gildea Acked-by: Jonathan Woithe Signed-off-by: Len Brown --- drivers/platform/x86/fujitsu-laptop.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 218b9a16ac3f..4c8897a84c68 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -66,7 +66,7 @@ #include #include #include -#ifdef CONFIG_LEDS_CLASS +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) #include #endif @@ -96,7 +96,7 @@ /* FUNC interface - responses */ #define UNSUPPORTED_CMD 0x80000000 -#ifdef CONFIG_LEDS_CLASS +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) /* FUNC interface - LED control */ #define FUNC_LED_OFF 0x1 #define FUNC_LED_ON 0x30001 @@ -176,7 +176,7 @@ static struct fujitsu_hotkey_t *fujitsu_hotkey; static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event); -#ifdef CONFIG_LEDS_CLASS +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) static enum led_brightness logolamp_get(struct led_classdev *cdev); static void logolamp_set(struct led_classdev *cdev, enum led_brightness brightness); @@ -257,7 +257,7 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2) return out_obj.integer.value; } -#ifdef CONFIG_LEDS_CLASS +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) /* LED class callbacks */ static void logolamp_set(struct led_classdev *cdev, @@ -911,7 +911,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); - #ifdef CONFIG_LEDS_CLASS + #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { result = led_classdev_register(&fujitsu->pf_device->dev, &logolamp_led); @@ -1204,7 +1204,7 @@ fail_acpi: static void __exit fujitsu_cleanup(void) { - #ifdef CONFIG_LEDS_CLASS + #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) if (fujitsu_hotkey->logolamp_registered != 0) led_classdev_unregister(&logolamp_led); -- cgit v1.2.3-59-g8ed1b From 14485c57270e8f3de2a25abaf93bae5712c97e9e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 31 Jul 2009 18:12:00 +0930 Subject: fujitsu-laptop: Correct redundant test device and acpi_driver_data(device) were tested just a few lines above. A simplified version of the semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E; @@ if (x == NULL || ...) { ... when forall return ...; } .. when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) ( *x == NULL | *x != NULL ) // Signed-off-by: Julia Lawall Acked-by: Jonathan Woithe Signed-off-by: Len Brown --- drivers/platform/x86/fujitsu-laptop.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 4c8897a84c68..0d42f444a447 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -745,9 +745,6 @@ static int acpi_fujitsu_remove(struct acpi_device *device, int type) fujitsu = acpi_driver_data(device); - if (!device || !acpi_driver_data(device)) - return -EINVAL; - fujitsu->acpi_handle = NULL; return 0; -- cgit v1.2.3-59-g8ed1b From 67059406219d30a36b7ca93f863eb1f3032f05ce Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 31 Jul 2009 08:43:56 +0000 Subject: fujitsu-laptop: remove superfluous NULL pointer checks This takes care of the following entries from Dan's list: drivers/platform/x86/fujitsu-laptop.c +327 set_lcd_level(13) warning: variable derefenced before check 'fujitsu' drivers/platform/x86/fujitsu-laptop.c +358 set_lcd_level_alt(13) warning: variable derefenced before check 'fujitsu' Reported-by: Dan Carpenter Cc: corbet@lwn.net Cc: eteo@redhat.com Cc: Julia Lawall Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Jonathan Woithe Signed-off-by: Len Brown --- drivers/platform/x86/fujitsu-laptop.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 0d42f444a447..f9e3e3afca13 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -324,9 +324,6 @@ static int set_lcd_level(int level) if (level < 0 || level >= fujitsu->max_brightness) return -EINVAL; - if (!fujitsu) - return -EINVAL; - status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); if (ACPI_FAILURE(status)) { vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n"); @@ -355,9 +352,6 @@ static int set_lcd_level_alt(int level) if (level < 0 || level >= fujitsu->max_brightness) return -EINVAL; - if (!fujitsu) - return -EINVAL; - status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle); if (ACPI_FAILURE(status)) { vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n"); -- cgit v1.2.3-59-g8ed1b From 72afeeafe54853881a4e53dc78d538e249130ad8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 31 Jul 2009 18:16:02 +0930 Subject: fujitsu-laptop: driver [un]registration fixes * Move led_classdev_unregister() calls from fujitsu_cleanup() to acpi_fujitsu_hotkey_remove(). * Fix ordering in fujitsu_cleanup(). * Fix backlight_device_register() failure handling in fujitsu_init(). * Add missing sysfs group removal on failure to fujitsu_init(). * Add input device unregistering on failure to acpi_fujitsu_add() and acpi_fujitsu_hotkey_add(). * Add input device unregistering/freeing to acpi_fujitsu_remove() and acpi_fujitsu_hotkey_remove() (also remove superfluous 'device' and 'acpi_driver_data(device)' checks while at it). * Do few minor cleanups. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Jonathan Woithe Signed-off-by: Len Brown --- drivers/platform/x86/fujitsu-laptop.c | 86 +++++++++++++++++------------------ 1 file changed, 41 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f9e3e3afca13..b87a5a2084a9 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -691,7 +691,7 @@ static int acpi_fujitsu_add(struct acpi_device *device) result = acpi_bus_get_power(fujitsu->acpi_handle, &state); if (result) { printk(KERN_ERR "Error reading power state\n"); - goto end; + goto err_unregister_input_dev; } printk(KERN_INFO PREFIX "%s [%s] (%s)\n", @@ -722,22 +722,22 @@ static int acpi_fujitsu_add(struct acpi_device *device) return result; -end: +err_unregister_input_dev: + input_unregister_device(input); err_free_input_dev: input_free_device(input); err_stop: - return result; } static int acpi_fujitsu_remove(struct acpi_device *device, int type) { - struct fujitsu_t *fujitsu = NULL; + struct fujitsu_t *fujitsu = acpi_driver_data(device); + struct input_dev *input = fujitsu->input; - if (!device || !acpi_driver_data(device)) - return -EINVAL; + input_unregister_device(input); - fujitsu = acpi_driver_data(device); + input_free_device(input); fujitsu->acpi_handle = NULL; @@ -862,7 +862,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state); if (result) { printk(KERN_ERR "Error reading power state\n"); - goto end; + goto err_unregister_input_dev; } printk(KERN_INFO PREFIX "%s [%s] (%s)\n", @@ -902,7 +902,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); - #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { result = led_classdev_register(&fujitsu->pf_device->dev, &logolamp_led); @@ -925,33 +925,41 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) "LED handler for keyboard lamps, error %i\n", result); } } - #endif +#endif return result; -end: +err_unregister_input_dev: + input_unregister_device(input); err_free_input_dev: input_free_device(input); err_free_fifo: kfifo_free(fujitsu_hotkey->fifo); err_stop: - return result; } static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type) { - struct fujitsu_hotkey_t *fujitsu_hotkey = NULL; + struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device); + struct input_dev *input = fujitsu_hotkey->input; - if (!device || !acpi_driver_data(device)) - return -EINVAL; +#ifdef CONFIG_LEDS_CLASS + if (fujitsu_hotkey->logolamp_registered) + led_classdev_unregister(&logolamp_led); + + if (fujitsu_hotkey->kblamps_registered) + led_classdev_unregister(&kblamps_led); +#endif - fujitsu_hotkey = acpi_driver_data(device); + input_unregister_device(input); - fujitsu_hotkey->acpi_handle = NULL; + input_free_device(input); kfifo_free(fujitsu_hotkey->fifo); + fujitsu_hotkey->acpi_handle = NULL; + return 0; } @@ -1121,8 +1129,11 @@ static int __init fujitsu_init(void) fujitsu->bl_device = backlight_device_register("fujitsu-laptop", NULL, NULL, &fujitsubl_ops); - if (IS_ERR(fujitsu->bl_device)) - return PTR_ERR(fujitsu->bl_device); + if (IS_ERR(fujitsu->bl_device)) { + ret = PTR_ERR(fujitsu->bl_device); + fujitsu->bl_device = NULL; + goto fail_sysfs_group; + } max_brightness = fujitsu->max_brightness; fujitsu->bl_device->props.max_brightness = max_brightness - 1; fujitsu->bl_device->props.brightness = fujitsu->brightness_level; @@ -1162,32 +1173,22 @@ static int __init fujitsu_init(void) return 0; fail_hotkey1: - kfree(fujitsu_hotkey); - fail_hotkey: - platform_driver_unregister(&fujitsupf_driver); - fail_backlight: - if (fujitsu->bl_device) backlight_device_unregister(fujitsu->bl_device); - +fail_sysfs_group: + sysfs_remove_group(&fujitsu->pf_device->dev.kobj, + &fujitsupf_attribute_group); fail_platform_device2: - platform_device_del(fujitsu->pf_device); - fail_platform_device1: - platform_device_put(fujitsu->pf_device); - fail_platform_driver: - acpi_bus_unregister_driver(&acpi_fujitsu_driver); - fail_acpi: - kfree(fujitsu); return ret; @@ -1195,28 +1196,23 @@ fail_acpi: static void __exit fujitsu_cleanup(void) { - #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) - if (fujitsu_hotkey->logolamp_registered != 0) - led_classdev_unregister(&logolamp_led); + acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver); - if (fujitsu_hotkey->kblamps_registered != 0) - led_classdev_unregister(&kblamps_led); - #endif + kfree(fujitsu_hotkey); - sysfs_remove_group(&fujitsu->pf_device->dev.kobj, - &fujitsupf_attribute_group); - platform_device_unregister(fujitsu->pf_device); platform_driver_unregister(&fujitsupf_driver); + if (fujitsu->bl_device) backlight_device_unregister(fujitsu->bl_device); - acpi_bus_unregister_driver(&acpi_fujitsu_driver); + sysfs_remove_group(&fujitsu->pf_device->dev.kobj, + &fujitsupf_attribute_group); - kfree(fujitsu); + platform_device_unregister(fujitsu->pf_device); - acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver); + acpi_bus_unregister_driver(&acpi_fujitsu_driver); - kfree(fujitsu_hotkey); + kfree(fujitsu); printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n"); } -- cgit v1.2.3-59-g8ed1b From 84a6ce267296dabdf427ea4aff73dc58164863bb Mon Sep 17 00:00:00 2001 From: Jonathan Woithe Date: Fri, 31 Jul 2009 18:16:59 +0930 Subject: fujitsu-laptop: increment driver version Increment driver version to reflect the changes from this patch series. Signed-off-by: Jonathan Woithe Signed-off-by: Len Brown --- drivers/platform/x86/fujitsu-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index b87a5a2084a9..1ed3513a62a2 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -70,7 +70,7 @@ #include #endif -#define FUJITSU_DRIVER_VERSION "0.5.0" +#define FUJITSU_DRIVER_VERSION "0.6.0" #define FUJITSU_LCD_N_LEVELS 8 -- cgit v1.2.3-59-g8ed1b From 6d41839e762f8b8b03dbb97fd0d41b244d0bc902 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:32 +0000 Subject: eeepc-laptop: don't touch the pci slot if it was claimed by a different driver The whole point of registering as a PCI hotplug driver was to prevent conflict with pciehp. At the moment it happens to work because eeepc-laptop is loaded first, but it doesn't work the other way round. If pciehp is loaded first then we fail to claim the slot - we need to respect this and not handle hotplug events. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 222ffb892f22..69d73ed2c8ab 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -664,15 +664,20 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, static void eeepc_hotplug_work(struct work_struct *work) { struct pci_dev *dev; - struct pci_bus *bus = pci_find_bus(0, 1); - bool blocked; + struct pci_bus *bus; + bool blocked = eeepc_wlan_rfkill_blocked(); + + rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); + if (ehotk->hotplug_slot == NULL) + return; + + bus = pci_find_bus(0, 1); if (!bus) { pr_warning("Unable to find PCI bus 1?\n"); return; } - blocked = eeepc_wlan_rfkill_blocked(); if (!blocked) { dev = pci_get_slot(bus, 0); if (dev) { @@ -693,8 +698,6 @@ static void eeepc_hotplug_work(struct work_struct *work) pci_dev_put(dev); } } - - rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); } static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) -- cgit v1.2.3-59-g8ed1b From dcf443b5813074031a45b05ad9c57da98bcae329 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:33 +0000 Subject: eeepc-laptop: use a mutex to serialize pci hotplug (resume vs. notify) Commit d0265f0 "eeepc-laptop: fix hot-unplug on resume" used a workqueue to protect pci hotplug against multiple simultaneous calls during resume. It seems to work, but a mutex would be more appropriate. This is in preparation to fix the potential pci hotplug race on unload. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 69d73ed2c8ab..179010386981 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -143,7 +143,7 @@ struct eeepc_hotk { struct rfkill *bluetooth_rfkill; struct rfkill *wwan3g_rfkill; struct hotplug_slot *hotplug_slot; - struct work_struct hotplug_work; + struct mutex hotplug_lock; }; /* The actual device the driver binds to */ @@ -661,7 +661,7 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, return 0; } -static void eeepc_hotplug_work(struct work_struct *work) +static void eeepc_rfkill_hotplug(void) { struct pci_dev *dev; struct pci_bus *bus; @@ -669,13 +669,15 @@ static void eeepc_hotplug_work(struct work_struct *work) rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); + mutex_lock(&ehotk->hotplug_lock); + if (ehotk->hotplug_slot == NULL) - return; + goto out_unlock; bus = pci_find_bus(0, 1); if (!bus) { pr_warning("Unable to find PCI bus 1?\n"); - return; + goto out_unlock; } if (!blocked) { @@ -683,7 +685,7 @@ static void eeepc_hotplug_work(struct work_struct *work) if (dev) { /* Device already present */ pci_dev_put(dev); - return; + goto out_unlock; } dev = pci_scan_single_device(bus, 0); if (dev) { @@ -698,6 +700,9 @@ static void eeepc_hotplug_work(struct work_struct *work) pci_dev_put(dev); } } + +out_unlock: + mutex_unlock(&ehotk->hotplug_lock); } static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) @@ -705,7 +710,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) if (event != ACPI_NOTIFY_BUS_CHECK) return; - schedule_work(&ehotk->hotplug_work); + eeepc_rfkill_hotplug(); } static void eeepc_hotk_notify(struct acpi_device *device, u32 event) @@ -896,7 +901,7 @@ static int eeepc_hotk_resume(struct acpi_device *device) rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); - schedule_work(&ehotk->hotplug_work); + eeepc_rfkill_hotplug(); } if (ehotk->bluetooth_rfkill) @@ -1097,7 +1102,7 @@ static int eeepc_rfkill_init(struct device *dev) { int result = 0; - INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work); + mutex_init(&ehotk->hotplug_lock); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); -- cgit v1.2.3-59-g8ed1b From 07e84aa98f6b3a7278d3267f6f657955ed3eb973 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:34 +0000 Subject: eeepc-laptop: fix pci hotplug race on load and unload Wifi rfkill state changes can race with pci hotplug cleanup. A simple fix is to refresh the hotplug state just before deregistering the pci hotplug slot. There is also potential for a hotplug notification to fire too early during setup, while the structures it uses are still being initialised. (This could only happen if the BIOS performs hotplug itself; a bug triggered by removing the battery while hibernated). Avoid this by registering the notifier later. The same refresh mechanism is used to handle rfkill state changes which can now race with registration. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 77 ++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 179010386981..8dd86f73b844 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -667,37 +667,37 @@ static void eeepc_rfkill_hotplug(void) struct pci_bus *bus; bool blocked = eeepc_wlan_rfkill_blocked(); - rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); + if (ehotk->wlan_rfkill) + rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); mutex_lock(&ehotk->hotplug_lock); - if (ehotk->hotplug_slot == NULL) - goto out_unlock; - - bus = pci_find_bus(0, 1); - if (!bus) { - pr_warning("Unable to find PCI bus 1?\n"); - goto out_unlock; - } - - if (!blocked) { - dev = pci_get_slot(bus, 0); - if (dev) { - /* Device already present */ - pci_dev_put(dev); + if (ehotk->hotplug_slot) { + bus = pci_find_bus(0, 1); + if (!bus) { + pr_warning("Unable to find PCI bus 1?\n"); goto out_unlock; } - dev = pci_scan_single_device(bus, 0); - if (dev) { - pci_bus_assign_resources(bus); - if (pci_bus_add_device(dev)) - pr_err("Unable to hotplug wifi\n"); - } - } else { - dev = pci_get_slot(bus, 0); - if (dev) { - pci_remove_bus_device(dev); - pci_dev_put(dev); + + if (!blocked) { + dev = pci_get_slot(bus, 0); + if (dev) { + /* Device already present */ + pci_dev_put(dev); + goto out_unlock; + } + dev = pci_scan_single_device(bus, 0); + if (dev) { + pci_bus_assign_resources(bus); + if (pci_bus_add_device(dev)) + pr_err("Unable to hotplug wifi\n"); + } + } else { + dev = pci_get_slot(bus, 0); + if (dev) { + pci_remove_bus_device(dev); + pci_dev_put(dev); + } } } @@ -1029,14 +1029,22 @@ static void eeepc_rfkill_exit(void) { eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); - if (ehotk->wlan_rfkill) + if (ehotk->wlan_rfkill) { rfkill_unregister(ehotk->wlan_rfkill); + ehotk->wlan_rfkill = NULL; + } + /* + * Refresh pci hotplug in case the rfkill state was changed after + * eeepc_unregister_rfkill_notifier() + */ + eeepc_rfkill_hotplug(); + if (ehotk->hotplug_slot) + pci_hp_deregister(ehotk->hotplug_slot); + if (ehotk->bluetooth_rfkill) rfkill_unregister(ehotk->bluetooth_rfkill); if (ehotk->wwan3g_rfkill) rfkill_unregister(ehotk->wwan3g_rfkill); - if (ehotk->hotplug_slot) - pci_hp_deregister(ehotk->hotplug_slot); } static void eeepc_input_exit(void) @@ -1104,9 +1112,6 @@ static int eeepc_rfkill_init(struct device *dev) mutex_init(&ehotk->hotplug_lock); - eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); - eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); - result = eeepc_new_rfkill(&ehotk->wlan_rfkill, "eeepc-wlan", dev, RFKILL_TYPE_WLAN, CM_ASL_WLAN); @@ -1136,6 +1141,14 @@ static int eeepc_rfkill_init(struct device *dev) if (result == -EBUSY) result = 0; + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); + /* + * Refresh pci hotplug in case the rfkill state was changed during + * setup. + */ + eeepc_rfkill_hotplug(); + exit: if (result && result != -ENODEV) eeepc_rfkill_exit(); -- cgit v1.2.3-59-g8ed1b From 1e7798547fe6920ae27fb92c9202353e9e4c55db Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:35 +0000 Subject: eeepc-laptop: fix ordering of init and exit functions 1. input and backlight devices were registered after acpi notifications are enabled. This left a window where eeepc_hotk_notify() might find these devices in an inconsistent (half-initialized) state. -> Move all device registration into eeepc_hotk_add(), which is called before enabling acpi notifications. 2. input and backlight devices were unregistered before acpi notifications are disabled. This left a window where eeepc_hotk_notify() might find these devices in an inconsistent (half-destroyed) state. -> Move all device unregistration into eeepc_hotk_remove(), which is called after disabling acpi notifications. 3. The acpi driver was not freed if an error occured further down in eeepc_laptop_init(). -> The rest of eeepc_laptop_init() has been moved to eeepc_hotk_add(), so this is no longer a problem. 4. The acpi driver was unregistered before the platform driver. This left a window where a sysfs access could attempt to read the ehotk structure after it had been freed by eeepc_hotk_remove(). -> The acpi driver is now unregistered as the last step in eeepc_laptop_exit(), so this is no longer a problem. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 120 ++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 8dd86f73b844..cf47d1cd1a34 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -847,44 +847,6 @@ error_slot: return ret; } -static int eeepc_hotk_add(struct acpi_device *device) -{ - int result; - - if (!device) - return -EINVAL; - pr_notice(EEEPC_HOTK_NAME "\n"); - ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); - if (!ehotk) - return -ENOMEM; - ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; - ehotk->handle = device->handle; - strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); - strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); - device->driver_data = ehotk; - ehotk->device = device; - result = eeepc_hotk_check(); - if (result) - goto ehotk_fail; - - return 0; - - ehotk_fail: - kfree(ehotk); - ehotk = NULL; - - return result; -} - -static int eeepc_hotk_remove(struct acpi_device *device, int type) -{ - if (!device || !acpi_driver_data(device)) - return -EINVAL; - - kfree(ehotk); - return 0; -} - static int eeepc_hotk_resume(struct acpi_device *device) { if (ehotk->wlan_rfkill) { @@ -1066,19 +1028,6 @@ static void eeepc_hwmon_exit(void) eeepc_hwmon_device = NULL; } -static void __exit eeepc_laptop_exit(void) -{ - eeepc_backlight_exit(); - eeepc_rfkill_exit(); - eeepc_input_exit(); - eeepc_hwmon_exit(); - acpi_bus_unregister_driver(&eeepc_hotk_driver); - sysfs_remove_group(&platform_device->dev.kobj, - &platform_attribute_group); - platform_device_unregister(platform_device); - platform_driver_unregister(&platform_driver); -} - static int eeepc_new_rfkill(struct rfkill **rfkill, const char *name, struct device *dev, enum rfkill_type type, int cm) @@ -1193,21 +1142,27 @@ static int eeepc_hwmon_init(struct device *dev) return result; } -static int __init eeepc_laptop_init(void) +static int eeepc_hotk_add(struct acpi_device *device) { struct device *dev; int result; - if (acpi_disabled) - return -ENODEV; - result = acpi_bus_register_driver(&eeepc_hotk_driver); - if (result < 0) - return result; - if (!ehotk) { - acpi_bus_unregister_driver(&eeepc_hotk_driver); - return -ENODEV; - } + if (!device) + return -EINVAL; + pr_notice(EEEPC_HOTK_NAME "\n"); + ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); + if (!ehotk) + return -ENOMEM; + ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; + ehotk->handle = device->handle; + strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); + strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); + device->driver_data = ehotk; + ehotk->device = device; + result = eeepc_hotk_check(); + if (result) + goto fail_check; eeepc_enable_camera(); /* Register platform stuff */ @@ -1246,6 +1201,7 @@ static int __init eeepc_laptop_init(void) goto fail_rfkill; return 0; + fail_rfkill: eeepc_hwmon_exit(); fail_hwmon: @@ -1261,8 +1217,50 @@ fail_platform_device1: platform_driver_unregister(&platform_driver); fail_platform_driver: eeepc_input_exit(); +fail_check: + kfree(ehotk); + return result; } +static int eeepc_hotk_remove(struct acpi_device *device, int type) +{ + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + eeepc_backlight_exit(); + eeepc_rfkill_exit(); + eeepc_input_exit(); + eeepc_hwmon_exit(); + sysfs_remove_group(&platform_device->dev.kobj, + &platform_attribute_group); + platform_device_unregister(platform_device); + platform_driver_unregister(&platform_driver); + + kfree(ehotk); + return 0; +} + +static int __init eeepc_laptop_init(void) +{ + int result; + + if (acpi_disabled) + return -ENODEV; + result = acpi_bus_register_driver(&eeepc_hotk_driver); + if (result < 0) + return result; + if (!ehotk) { + acpi_bus_unregister_driver(&eeepc_hotk_driver); + return -ENODEV; + } + return 0; +} + +static void __exit eeepc_laptop_exit(void) +{ + acpi_bus_unregister_driver(&eeepc_hotk_driver); +} + module_init(eeepc_laptop_init); module_exit(eeepc_laptop_exit); -- cgit v1.2.3-59-g8ed1b From f2a9d5e8a649c606f520b7a7b9f4f46fba79c327 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:36 +0000 Subject: eeepc-laptop: make input device a child of the platform device Sysfs showed the ehotk input device as a "virtual" device - lies! The input device is provided by a physical device, the eeepc platform. This requires that we move the creation of the input device to come after platform device is created. Input initialization is moved from ehotk_check() [sic] to a new function called eeepc_input_init(). This brings the input device into line with the other eeepc-laptop devices. Also, refuse to load if we fail to register the input device. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 70 ++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index cf47d1cd1a34..298dac9c6ada 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -579,7 +579,6 @@ static void cmsg_quirks(void) static int eeepc_hotk_check(void) { - const struct key_entry *key; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; int result; @@ -604,31 +603,6 @@ static int eeepc_hotk_check(void) pr_info("Get control methods supported: 0x%x\n", ehotk->cm_supported); } - ehotk->inputdev = input_allocate_device(); - if (!ehotk->inputdev) { - pr_info("Unable to allocate input device\n"); - return 0; - } - ehotk->inputdev->name = "Asus EeePC extra buttons"; - ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; - ehotk->inputdev->id.bustype = BUS_HOST; - ehotk->inputdev->getkeycode = eeepc_getkeycode; - ehotk->inputdev->setkeycode = eeepc_setkeycode; - - for (key = eeepc_keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, ehotk->inputdev->evbit); - set_bit(key->keycode, ehotk->inputdev->keybit); - break; - } - } - result = input_register_device(ehotk->inputdev); - if (result) { - pr_info("Unable to register input device\n"); - input_free_device(ehotk->inputdev); - return 0; - } } else { pr_err("Hotkey device not present, aborting\n"); return -EINVAL; @@ -1142,6 +1116,40 @@ static int eeepc_hwmon_init(struct device *dev) return result; } +static int eeepc_input_init(struct device *dev) +{ + const struct key_entry *key; + int result; + + ehotk->inputdev = input_allocate_device(); + if (!ehotk->inputdev) { + pr_info("Unable to allocate input device\n"); + return -ENOMEM; + } + ehotk->inputdev->name = "Asus EeePC extra buttons"; + ehotk->inputdev->dev.parent = dev; + ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; + ehotk->inputdev->id.bustype = BUS_HOST; + ehotk->inputdev->getkeycode = eeepc_getkeycode; + ehotk->inputdev->setkeycode = eeepc_setkeycode; + + for (key = eeepc_keymap; key->type != KE_END; key++) { + switch (key->type) { + case KE_KEY: + set_bit(EV_KEY, ehotk->inputdev->evbit); + set_bit(key->keycode, ehotk->inputdev->keybit); + break; + } + } + result = input_register_device(ehotk->inputdev); + if (result) { + pr_info("Unable to register input device\n"); + input_free_device(ehotk->inputdev); + return result; + } + return 0; +} + static int eeepc_hotk_add(struct acpi_device *device) { struct device *dev; @@ -1162,7 +1170,7 @@ static int eeepc_hotk_add(struct acpi_device *device) result = eeepc_hotk_check(); if (result) - goto fail_check; + goto fail_platform_driver; eeepc_enable_camera(); /* Register platform stuff */ @@ -1192,6 +1200,10 @@ static int eeepc_hotk_add(struct acpi_device *device) pr_info("Backlight controlled by ACPI video " "driver\n"); + result = eeepc_input_init(dev); + if (result) + goto fail_input; + result = eeepc_hwmon_init(dev); if (result) goto fail_hwmon; @@ -1205,6 +1217,8 @@ static int eeepc_hotk_add(struct acpi_device *device) fail_rfkill: eeepc_hwmon_exit(); fail_hwmon: + eeepc_input_exit(); +fail_input: eeepc_backlight_exit(); fail_backlight: sysfs_remove_group(&platform_device->dev.kobj, @@ -1216,8 +1230,6 @@ fail_platform_device2: fail_platform_device1: platform_driver_unregister(&platform_driver); fail_platform_driver: - eeepc_input_exit(); -fail_check: kfree(ehotk); return result; -- cgit v1.2.3-59-g8ed1b From ffb03575284e0f72d7ea001178c793afa265b8b5 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:37 +0000 Subject: eeepc-laptop: remove redundant rfkill_set_sw_state in resume handler rfkill_set_sw_state() will already be called by eeepc_rfkill_hotplug(). Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 298dac9c6ada..7f7573a30ddc 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -835,8 +835,7 @@ static int eeepc_hotk_resume(struct acpi_device *device) wlan = get_acpi(CM_ASL_WLAN); set_acpi(CM_ASL_WLAN, wlan); - rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); - + /* Refresh both rfkill state and pci hotplug */ eeepc_rfkill_hotplug(); } -- cgit v1.2.3-59-g8ed1b From a47461011a0f5110c497b9b163d1125d258418b2 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:38 +0000 Subject: eeepc-laptop: check the 3G rfkill state on resume All the rfkill devices are treated as "persistent", 3G is no exception. This means their state may change over hibernation. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 7f7573a30ddc..8a3200430f10 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -842,6 +842,9 @@ static int eeepc_hotk_resume(struct acpi_device *device) if (ehotk->bluetooth_rfkill) rfkill_set_sw_state(ehotk->bluetooth_rfkill, get_acpi(CM_ASL_BLUETOOTH) != 1); + if (ehotk->wwan3g_rfkill) + rfkill_set_sw_state(ehotk->wwan3g_rfkill, + get_acpi(CM_ASL_3G) != 1); return 0; } -- cgit v1.2.3-59-g8ed1b From c1edd99f1c2b0285ce810d217180bf37bbae550e Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:39 +0000 Subject: eeepc-laptop: correct the description of the hibernation abort bug Actually it is only the LED which is affected. The bios bug does not disable the wifi. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 8a3200430f10..df68ae6a55d5 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -826,11 +826,10 @@ static int eeepc_hotk_resume(struct acpi_device *device) if (ehotk->wlan_rfkill) { bool wlan; - /* Workaround - it seems that _PTS disables the wireless - without notification or changing the value read by WLAN. - Normally this is fine because the correct value is restored - from the non-volatile storage on resume, but we need to do - it ourself if case suspend is aborted, or we lose wireless. + /* + * Work around bios bug - acpi _PTS turns off the wireless led + * during suspend. Normally it restores it on resume, but + * we should kick it ourselves in case suspend is aborted. */ wlan = get_acpi(CM_ASL_WLAN); set_acpi(CM_ASL_WLAN, wlan); -- cgit v1.2.3-59-g8ed1b From c200da5d2900df9c24fb8041870d92a4175bbef3 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:40 +0000 Subject: eeepc-laptop: switch to dev_pm_ops This also involves switching the resume handler from the acpi device to the platform device. Using the more fine grained handlers allows two improvements: 1. We only need to recheck rfkill state after resume from hibernation. 2. The wireless LED workaround accounts for up to 1.1s out of 1.7s resuming devices (when wireless is enabled). We can limit the workaround to thaw(), so that it only delays suspend to disk. The workaround is only likely to help when hibernation is aborted. Suspend to ram cannot be aborted by the user. Device suspend errors may well happen before eeepc-laptop would even be frozen. Suspend errors which happen after that could be pretty funky anyway. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index df68ae6a55d5..1c948604af94 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -150,10 +150,19 @@ struct eeepc_hotk { static struct eeepc_hotk *ehotk; /* Platform device/driver */ +static int eeepc_hotk_thaw(struct device *device); +static int eeepc_hotk_restore(struct device *device); + +static struct dev_pm_ops eeepc_pm_ops = { + .thaw = eeepc_hotk_thaw, + .restore = eeepc_hotk_restore, +}; + static struct platform_driver platform_driver = { .driver = { .name = EEEPC_HOTK_FILE, .owner = THIS_MODULE, + .pm = &eeepc_pm_ops, } }; @@ -192,7 +201,6 @@ static struct key_entry eeepc_keymap[] = { */ static int eeepc_hotk_add(struct acpi_device *device); static int eeepc_hotk_remove(struct acpi_device *device, int type); -static int eeepc_hotk_resume(struct acpi_device *device); static void eeepc_hotk_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id eeepc_device_ids[] = { @@ -209,7 +217,6 @@ static struct acpi_driver eeepc_hotk_driver = { .ops = { .add = eeepc_hotk_add, .remove = eeepc_hotk_remove, - .resume = eeepc_hotk_resume, .notify = eeepc_hotk_notify, }, }; @@ -821,7 +828,7 @@ error_slot: return ret; } -static int eeepc_hotk_resume(struct acpi_device *device) +static int eeepc_hotk_thaw(struct device *device) { if (ehotk->wlan_rfkill) { bool wlan; @@ -829,14 +836,20 @@ static int eeepc_hotk_resume(struct acpi_device *device) /* * Work around bios bug - acpi _PTS turns off the wireless led * during suspend. Normally it restores it on resume, but - * we should kick it ourselves in case suspend is aborted. + * we should kick it ourselves in case hibernation is aborted. */ wlan = get_acpi(CM_ASL_WLAN); set_acpi(CM_ASL_WLAN, wlan); + } + + return 0; +} - /* Refresh both rfkill state and pci hotplug */ +static int eeepc_hotk_restore(struct device *device) +{ + /* Refresh both wlan rfkill state and pci hotplug */ + if (ehotk->wlan_rfkill) eeepc_rfkill_hotplug(); - } if (ehotk->bluetooth_rfkill) rfkill_set_sw_state(ehotk->bluetooth_rfkill, -- cgit v1.2.3-59-g8ed1b From d1ec9c3d434d94e3674bcf433e8e8e7462b8e1c0 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:41 +0000 Subject: eeepc-laptop: add rfkill support for the Wimax in ASUS Eee PC 1000HG Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 1c948604af94..c9febf4b1faa 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -142,6 +142,7 @@ struct eeepc_hotk { struct rfkill *wlan_rfkill; struct rfkill *bluetooth_rfkill; struct rfkill *wwan3g_rfkill; + struct rfkill *wimax_rfkill; struct hotplug_slot *hotplug_slot; struct mutex hotplug_lock; }; @@ -857,6 +858,9 @@ static int eeepc_hotk_restore(struct device *device) if (ehotk->wwan3g_rfkill) rfkill_set_sw_state(ehotk->wwan3g_rfkill, get_acpi(CM_ASL_3G) != 1); + if (ehotk->wimax_rfkill) + rfkill_set_sw_state(ehotk->wimax_rfkill, + get_acpi(CM_ASL_WIMAX) != 1); return 0; } @@ -995,6 +999,8 @@ static void eeepc_rfkill_exit(void) rfkill_unregister(ehotk->bluetooth_rfkill); if (ehotk->wwan3g_rfkill) rfkill_unregister(ehotk->wwan3g_rfkill); + if (ehotk->wimax_rfkill) + rfkill_unregister(ehotk->wimax_rfkill); } static void eeepc_input_exit(void) @@ -1070,6 +1076,13 @@ static int eeepc_rfkill_init(struct device *dev) if (result && result != -ENODEV) goto exit; + result = eeepc_new_rfkill(&ehotk->wimax_rfkill, + "eeepc-wimax", dev, + RFKILL_TYPE_WIMAX, CM_ASL_WIMAX); + + if (result && result != -ENODEV) + goto exit; + result = eeepc_setup_pci_hotplug(); /* * If we get -EBUSY then something else is handling the PCI hotplug - -- cgit v1.2.3-59-g8ed1b From 1d4a3800c764d111d67462a14589ed1611b2f55e Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:46 +0000 Subject: asus-laptop: Show HRWS in infos and fix output format Show HRWS in /sys/platform/devices/asus-laptop/infos. HRWS is a bitfield used to get information about Hardware available in the laptop. Also change sprintf format from 0x%04x to %#x. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index db657bbeec90..23449508d86b 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -516,7 +516,17 @@ static ssize_t show_infos(struct device *dev, */ rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); if (!ACPI_FAILURE(rv)) - len += sprintf(page + len, "SFUN value : 0x%04x\n", + len += sprintf(page + len, "SFUN value : %#x\n", + (uint) temp); + /* + * The HWRS method return informations about the hardware. + * 0x80 bit is for WLAN, 0x100 for Bluetooth. + * The significance of others is yet to be found. + * If we don't find the method, we assume the device are present. + */ + rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp); + if (!ACPI_FAILURE(rv)) + len += sprintf(page + len, "HRWS value : %#x\n", (uint) temp); /* * Another value for userspace: the ASYM method returns 0x02 for @@ -527,7 +537,7 @@ static ssize_t show_infos(struct device *dev, */ rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); if (!ACPI_FAILURE(rv)) - len += sprintf(page + len, "ASYM value : 0x%04x\n", + len += sprintf(page + len, "ASYM value : %#x\n", (uint) temp); if (asus_info) { snprintf(buf, 16, "%d", asus_info->length); -- cgit v1.2.3-59-g8ed1b From abfa57e15acaa6e1ec567c250e5212bc55d79e43 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:47 +0000 Subject: asus-laptop: Add *_led_get() functions Add support for getting led brightness directly from the hardware. Currently we don't need it, but it is needed to support keyboard backlight/led. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 23449508d86b..88cc9a1045b4 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -246,12 +246,15 @@ static struct workqueue_struct *led_workqueue; #define ASUS_LED(object, ledname) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value); \ + static enum led_brightness object##_led_get( \ + struct led_classdev *led_cdev); \ static void object##_led_update(struct work_struct *ignored); \ static int object##_led_wk; \ static DECLARE_WORK(object##_led_work, object##_led_update); \ static struct led_classdev object##_led = { \ .name = "asus::" ledname, \ .brightness_set = object##_led_set, \ + .brightness_get = object##_led_get, \ } ASUS_LED(mled, "mail"); @@ -399,6 +402,11 @@ static void write_status(acpi_handle handle, int out, int mask) { \ int value = object##_led_wk; \ write_status(object##_set_handle, value, (mask)); \ + } \ + static enum led_brightness object##_led_get( \ + struct led_classdev *led_cdev) \ + { \ + return led_cdev->brightness; \ } ASUS_LED_HANDLER(mled, MLED_ON); -- cgit v1.2.3-59-g8ed1b From f641375b65f64e83be8be68ae1ebce21ee4fd578 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:48 +0000 Subject: asus-laptop: Map X50R hotkeys Map some new hotkeys found on X50R. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 88cc9a1045b4..410e545e427b 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -285,6 +285,9 @@ static struct key_entry asus_keymap[] = { {KE_KEY, 0x51, KEY_WWW}, {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ {KE_KEY, 0x5D, KEY_WLAN}, + {KE_KEY, 0x5E, KEY_WLAN}, + {KE_KEY, 0x5F, KEY_WLAN}, + {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ {KE_KEY, 0x82, KEY_CAMERA}, -- cgit v1.2.3-59-g8ed1b From 977c328d81e31fde70c5ba381d9cf7357451dd74 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:49 +0000 Subject: asus-laptop: set maximum led brightness Set the right maximum brightness which is one, because they can only be on or off. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 410e545e427b..652902e6f205 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -243,7 +243,7 @@ static struct backlight_ops asusbl_ops = { * potentially bad time, such as a timer interrupt. */ static struct workqueue_struct *led_workqueue; -#define ASUS_LED(object, ledname) \ +#define ASUS_LED(object, ledname, max) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value); \ static enum led_brightness object##_led_get( \ @@ -255,13 +255,14 @@ static struct workqueue_struct *led_workqueue; .name = "asus::" ledname, \ .brightness_set = object##_led_set, \ .brightness_get = object##_led_get, \ + .max_brightness = max \ } -ASUS_LED(mled, "mail"); -ASUS_LED(tled, "touchpad"); -ASUS_LED(rled, "record"); -ASUS_LED(pled, "phone"); -ASUS_LED(gled, "gaming"); +ASUS_LED(mled, "mail", 1); +ASUS_LED(tled, "touchpad", 1); +ASUS_LED(rled, "record", 1); +ASUS_LED(pled, "phone", 1); +ASUS_LED(gled, "gaming", 1); struct key_entry { char type; -- cgit v1.2.3-59-g8ed1b From b7d3fbc2ed624cc216adda0f2574570e6d6d6aed Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:50 +0000 Subject: asus-laptop: Add support for Keyboard backlight Add support for keyboard backlight found in Asus U50VG. The SMC driver for the Apples does it via LED. To be consistent with that we create /sys/class/leds/asus::kbd_backlight/ to control the keyboard backlight. SLKB and GLKB are used to get/set the backlight. On the U50VG is supports 4 brightness level, but this may change with other models. SLKB take a 8 bit integer where the higher bit is used to toggle the backlight, and the over 7 bits control the brightness level. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 79 +++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 652902e6f205..0fb4e5971516 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -86,6 +86,7 @@ #define GLED_ON 0x40 //Gaming LED #define LCD_ON 0x80 //LCD backlight #define GPS_ON 0x100 //GPS +#define KEY_ON 0x200 //Keyboard backlight #define ASUS_LOG ASUS_HOTK_FILE ": " #define ASUS_ERR KERN_ERR ASUS_LOG @@ -172,6 +173,10 @@ ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */ ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); +/* Keyboard light */ +ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB"); +ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB"); + /* * This is the main structure, we can use it to store anything interesting * about the hotk device @@ -263,6 +268,7 @@ ASUS_LED(tled, "touchpad", 1); ASUS_LED(rled, "record", 1); ASUS_LED(pled, "phone", 1); ASUS_LED(gled, "gaming", 1); +ASUS_LED(kled, "kbd_backlight", 3); struct key_entry { char type; @@ -419,6 +425,60 @@ ASUS_LED_HANDLER(rled, RLED_ON); ASUS_LED_HANDLER(tled, TLED_ON); ASUS_LED_HANDLER(gled, GLED_ON); +/* + * Keyboard backlight + */ +static int get_kled_lvl(void) +{ + unsigned long long kblv; + struct acpi_object_list params; + union acpi_object in_obj; + acpi_status rv; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = 2; + + rv = acpi_evaluate_integer(kled_get_handle, NULL, ¶ms, &kblv); + if (ACPI_FAILURE(rv)) { + pr_warning("Error reading kled level\n"); + return 0; + } + return kblv; +} + +static int set_kled_lvl(int kblv) +{ + if (kblv > 0) + kblv = (1 << 7) | (kblv & 0x7F); + else + kblv = 0; + + if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) { + pr_warning("Keyboard LED display write failed\n"); + return -EINVAL; + } + return 0; +} + +static void kled_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + kled_led_wk = value; + queue_work(led_workqueue, &kled_led_work); +} + +static void kled_led_update(struct work_struct *ignored) +{ + set_kled_lvl(kled_led_wk); +} + +static enum led_brightness kled_led_get(struct led_classdev *led_cdev) +{ + return get_kled_lvl(); +} + static int get_lcd_state(void) { return read_status(LCD_ON); @@ -1059,6 +1119,9 @@ static int asus_hotk_get_info(void) ASUS_HANDLE_INIT(ledd_set); + ASUS_HANDLE_INIT(kled_set); + ASUS_HANDLE_INIT(kled_get); + /* * The HWRS method return informations about the hardware. * 0x80 bit is for WLAN, 0x100 for Bluetooth. @@ -1190,6 +1253,10 @@ static int asus_hotk_add(struct acpi_device *device) /* LCD Backlight is on by default */ write_status(NULL, 1, LCD_ON); + /* Keyboard Backlight is on by default */ + if (kled_set_handle) + set_kled_lvl(1); + /* LED display is off by default */ hotk->ledd_status = 0xFFF; @@ -1244,6 +1311,7 @@ static void asus_led_exit(void) ASUS_LED_UNREGISTER(pled); ASUS_LED_UNREGISTER(rled); ASUS_LED_UNREGISTER(gled); + ASUS_LED_UNREGISTER(kled); } static void asus_input_exit(void) @@ -1323,13 +1391,20 @@ static int asus_led_init(struct device *dev) if (rv) goto out4; + if (kled_set_handle && kled_get_handle) + rv = ASUS_LED_REGISTER(kled, dev); + if (rv) + goto out5; + led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!led_workqueue) - goto out5; + goto out6; return 0; -out5: +out6: rv = -ENOMEM; + ASUS_LED_UNREGISTER(kled); +out5: ASUS_LED_UNREGISTER(gled); out4: ASUS_LED_UNREGISTER(pled); -- cgit v1.2.3-59-g8ed1b From dc79526078d2c0f01445e54e1d9fdf7c15ffd63d Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:51 +0000 Subject: asus-laptop: handle keyboard backlight keys Add support for the Fn+F3/Fn+F4 keys and map them as KEY_KBDILLUMUP and KEY_KBDILLUMDOWN. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 0fb4e5971516..dd926b913ec9 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -301,6 +301,8 @@ static struct key_entry asus_keymap[] = { {KE_KEY, 0x8A, KEY_PROG1}, {KE_KEY, 0x95, KEY_MEDIA}, {KE_KEY, 0x99, KEY_PHONE}, + {KE_KEY, 0xc4, KEY_KBDILLUMUP}, + {KE_KEY, 0xc5, KEY_KBDILLUMDOWN}, {KE_END, 0}, }; -- cgit v1.2.3-59-g8ed1b From 4644d0e5bd1412bbaed77e46c0c3376c6d060a74 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:52 +0000 Subject: asus-laptop: Add suport for another "Media" key Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index dd926b913ec9..0325f7c2d7a0 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -288,6 +288,7 @@ static struct key_entry asus_keymap[] = { {KE_KEY, 0x41, KEY_NEXTSONG}, {KE_KEY, 0x43, KEY_STOPCD}, {KE_KEY, 0x45, KEY_PLAYPAUSE}, + {KE_KEY, 0x4c, KEY_MEDIA}, {KE_KEY, 0x50, KEY_EMAIL}, {KE_KEY, 0x51, KEY_WWW}, {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ -- cgit v1.2.3-59-g8ed1b From 0aa20f7d720ed1feeb74df8c63a6427d9a2d3ebd Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:53 +0000 Subject: asus-laptop: Add "calculator" hotkey Found on UX50V. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 0325f7c2d7a0..5b912cc5cbee 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -291,6 +291,7 @@ static struct key_entry asus_keymap[] = { {KE_KEY, 0x4c, KEY_MEDIA}, {KE_KEY, 0x50, KEY_EMAIL}, {KE_KEY, 0x51, KEY_WWW}, + {KE_KEY, 0x55, KEY_CALC}, {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ {KE_KEY, 0x5D, KEY_WLAN}, {KE_KEY, 0x5E, KEY_WLAN}, -- cgit v1.2.3-59-g8ed1b From aeb41b852fe90764b75ef7a9f185ca94696af6ff Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 28 Aug 2009 19:03:11 -0400 Subject: eeepc-laptop: whitespace for checkpatch.pl checkpatch doesn't like tab+space for a return statement. WARNING: suspect code indent for conditional statements (8, 17) + if (!device) + return -EINVAL; Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index c9febf4b1faa..819c685fe9cf 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1183,7 +1183,7 @@ static int eeepc_hotk_add(struct acpi_device *device) int result; if (!device) - return -EINVAL; + return -EINVAL; pr_notice(EEEPC_HOTK_NAME "\n"); ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); if (!ehotk) @@ -1265,7 +1265,7 @@ fail_platform_driver: static int eeepc_hotk_remove(struct acpi_device *device, int type) { if (!device || !acpi_driver_data(device)) - return -EINVAL; + return -EINVAL; eeepc_backlight_exit(); eeepc_rfkill_exit(); -- cgit v1.2.3-59-g8ed1b From b2deadd53c3630786e73746fb0ad8450f4e015bf Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 24 Jul 2009 10:56:43 +0800 Subject: ACPICA: Move predefined repair code to new file, no functional change New file is nsrepair.c. This is in preparation for additional errror correcting code. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/Makefile | 2 +- drivers/acpi/acpica/acnamesp.h | 17 +++++ drivers/acpi/acpica/nspredef.c | 120 +------------------------------- drivers/acpi/acpica/nsrepair.c | 151 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+), 119 deletions(-) create mode 100644 drivers/acpi/acpica/nsrepair.c (limited to 'drivers') diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 0e7d56185f6d..e7973bc16846 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -28,7 +28,7 @@ acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o acpi-y += nsaccess.o nsload.o nssearch.o nsxfeval.o \ nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \ nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \ - nsparse.o nspredef.o + nsparse.o nspredef.o nsrepair.o acpi-$(ACPI_FUTURE_USAGE) += nsdumpdv.o diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index a78e02f62d5e..908cfdd3b895 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -73,6 +73,14 @@ #define ACPI_NS_WALK_UNLOCK 0x01 #define ACPI_NS_WALK_TEMP_NODES 0x02 +/* Object is not a package element */ + +#define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX + +/* Always emit warning message, not dependent on node flags */ + +#define ACPI_WARN_ALWAYS 0 + /* * nsinit - Namespace initialization */ @@ -261,6 +269,15 @@ acpi_status acpi_ns_get_attached_data(struct acpi_namespace_node *node, acpi_object_handler handler, void **data); +/* + * nsrepair - return object repair for predefined methods/objects + */ +acpi_status +acpi_ns_repair_object(struct acpi_predefined_data *data, + u32 expected_btypes, + u32 package_index, + union acpi_operand_object **return_object_ptr); + /* * nssearch - Namespace searching and entry */ diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 1dc1a4737aa9..e3f08dcb5275 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -91,12 +91,6 @@ static acpi_status acpi_ns_check_reference(struct acpi_predefined_data *data, union acpi_operand_object *return_object); -static acpi_status -acpi_ns_repair_object(struct acpi_predefined_data *data, - u32 expected_btypes, - u32 package_index, - union acpi_operand_object **return_object_ptr); - static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes); /* @@ -111,14 +105,6 @@ static const char *acpi_rtype_names[] = { "/Reference", }; -/* Object is not a package element */ - -#define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX - -/* Always emit warning message, not dependent on node flags */ - -#define ACPI_WARN_ALWAYS 0 - /******************************************************************************* * * FUNCTION: acpi_ns_check_predefined_names @@ -580,8 +566,8 @@ acpi_ns_check_package(struct acpi_predefined_data *data, case ACPI_PTYPE2_COUNT: /* - * These types all return a single package that consists of a variable - * number of sub-packages + * These types all return a single package that consists of a + * variable number of sub-packages. */ for (i = 0; i < count; i++) { sub_package = *elements; @@ -977,108 +963,6 @@ acpi_ns_check_reference(struct acpi_predefined_data *data, return (AE_AML_OPERAND_TYPE); } -/******************************************************************************* - * - * FUNCTION: acpi_ns_repair_object - * - * PARAMETERS: Data - Pointer to validation data structure - * expected_btypes - Object types expected - * package_index - Index of object within parent package (if - * applicable - ACPI_NOT_PACKAGE_ELEMENT - * otherwise) - * return_object_ptr - Pointer to the object returned from the - * evaluation of a method or object - * - * RETURN: Status. AE_OK if repair was successful. - * - * DESCRIPTION: Attempt to repair/convert a return object of a type that was - * not expected. - * - ******************************************************************************/ - -static acpi_status -acpi_ns_repair_object(struct acpi_predefined_data *data, - u32 expected_btypes, - u32 package_index, - union acpi_operand_object **return_object_ptr) -{ - union acpi_operand_object *return_object = *return_object_ptr; - union acpi_operand_object *new_object; - acpi_size length; - - switch (return_object->common.type) { - case ACPI_TYPE_BUFFER: - - /* Does the method/object legally return a string? */ - - if (!(expected_btypes & ACPI_RTYPE_STRING)) { - return (AE_AML_OPERAND_TYPE); - } - - /* - * Have a Buffer, expected a String, convert. Use a to_string - * conversion, no transform performed on the buffer data. The best - * example of this is the _BIF method, where the string data from - * the battery is often (incorrectly) returned as buffer object(s). - */ - length = 0; - while ((length < return_object->buffer.length) && - (return_object->buffer.pointer[length])) { - length++; - } - - /* Allocate a new string object */ - - new_object = acpi_ut_create_string_object(length); - if (!new_object) { - return (AE_NO_MEMORY); - } - - /* - * Copy the raw buffer data with no transform. String is already NULL - * terminated at Length+1. - */ - ACPI_MEMCPY(new_object->string.pointer, - return_object->buffer.pointer, length); - - /* - * If the original object is a package element, we need to: - * 1. Set the reference count of the new object to match the - * reference count of the old object. - * 2. Decrement the reference count of the original object. - */ - if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { - new_object->common.reference_count = - return_object->common.reference_count; - - if (return_object->common.reference_count > 1) { - return_object->common.reference_count--; - } - - ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, - data->node_flags, - "Converted Buffer to expected String at index %u", - package_index)); - } else { - ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, - data->node_flags, - "Converted Buffer to expected String")); - } - - /* Delete old object, install the new return object */ - - acpi_ut_remove_reference(return_object); - *return_object_ptr = new_object; - data->flags |= ACPI_OBJECT_REPAIRED; - return (AE_OK); - - default: - break; - } - - return (AE_AML_OPERAND_TYPE); -} - /******************************************************************************* * * FUNCTION: acpi_ns_get_expected_types diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c new file mode 100644 index 000000000000..b64751eacc53 --- /dev/null +++ b/drivers/acpi/acpica/nsrepair.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Module Name: nsrepair - Repair for objects returned by predefined methods + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2009, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acnamesp.h" +#include "acpredef.h" + +#define _COMPONENT ACPI_NAMESPACE +ACPI_MODULE_NAME("nsrepair") + +/******************************************************************************* + * + * FUNCTION: acpi_ns_repair_object + * + * PARAMETERS: Data - Pointer to validation data structure + * expected_btypes - Object types expected + * package_index - Index of object within parent package (if + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) + * return_object_ptr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if repair was successful. + * + * DESCRIPTION: Attempt to repair/convert a return object of a type that was + * not expected. + * + ******************************************************************************/ +acpi_status +acpi_ns_repair_object(struct acpi_predefined_data *data, + u32 expected_btypes, + u32 package_index, + union acpi_operand_object **return_object_ptr) +{ + union acpi_operand_object *return_object = *return_object_ptr; + union acpi_operand_object *new_object; + acpi_size length; + + switch (return_object->common.type) { + case ACPI_TYPE_BUFFER: + + /* Does the method/object legally return a string? */ + + if (!(expected_btypes & ACPI_RTYPE_STRING)) { + return (AE_AML_OPERAND_TYPE); + } + + /* + * Have a Buffer, expected a String, convert. Use a to_string + * conversion, no transform performed on the buffer data. The best + * example of this is the _BIF method, where the string data from + * the battery is often (incorrectly) returned as buffer object(s). + */ + length = 0; + while ((length < return_object->buffer.length) && + (return_object->buffer.pointer[length])) { + length++; + } + + /* Allocate a new string object */ + + new_object = acpi_ut_create_string_object(length); + if (!new_object) { + return (AE_NO_MEMORY); + } + + /* + * Copy the raw buffer data with no transform. String is already NULL + * terminated at Length+1. + */ + ACPI_MEMCPY(new_object->string.pointer, + return_object->buffer.pointer, length); + + /* + * If the original object is a package element, we need to: + * 1. Set the reference count of the new object to match the + * reference count of the old object. + * 2. Decrement the reference count of the original object. + */ + if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { + new_object->common.reference_count = + return_object->common.reference_count; + + if (return_object->common.reference_count > 1) { + return_object->common.reference_count--; + } + + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, + data->node_flags, + "Converted Buffer to expected String at index %u", + package_index)); + } else { + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, + data->node_flags, + "Converted Buffer to expected String")); + } + + /* Delete old object, install the new return object */ + + acpi_ut_remove_reference(return_object); + *return_object_ptr = new_object; + data->flags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); + + default: + break; + } + + return (AE_AML_OPERAND_TYPE); +} -- cgit v1.2.3-59-g8ed1b From e5f69d6ef7a6b0dbad8d4c00d83009960be02155 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 24 Jul 2009 11:03:09 +0800 Subject: ACPICA: Add repair for predefined methods that return nested packages Fixes a problem where a predefined method is defined to return a variable-length Package of sub-packages. If the length is one, the BIOS code occasionally creates a simple single package with no sub-packages. This code attempts to fix the problem by wrapping a new package object around the existing package. ACPICA BZ 790. http://acpica.org/bugzilla/show_bug.cgi?id=790 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acnamesp.h | 4 ++++ drivers/acpi/acpica/nspredef.c | 30 ++++++++++++++++++++++-- drivers/acpi/acpica/nsrepair.c | 52 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 908cfdd3b895..f75a7a01b875 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -278,6 +278,10 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, u32 package_index, union acpi_operand_object **return_object_ptr); +acpi_status +acpi_ns_repair_package_list(struct acpi_predefined_data *data, + union acpi_operand_object **obj_desc_ptr); + /* * nssearch - Namespace searching and entry */ diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index e3f08dcb5275..0091504df074 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -566,9 +566,35 @@ acpi_ns_check_package(struct acpi_predefined_data *data, case ACPI_PTYPE2_COUNT: /* - * These types all return a single package that consists of a - * variable number of sub-packages. + * These types all return a single Package that consists of a + * variable number of sub-Packages. + * + * First, ensure that the first element is a sub-Package. If not, + * the BIOS may have incorrectly returned the object as a single + * package instead of a Package of Packages (a common error if + * there is only one entry). We may be able to repair this by + * wrapping the returned Package with a new outer Package. */ + if ((*elements)->common.type != ACPI_TYPE_PACKAGE) { + + /* Create the new outer package and populate it */ + + status = + acpi_ns_repair_package_list(data, + return_object_ptr); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Update locals to point to the new package (of 1 element) */ + + return_object = *return_object_ptr; + elements = return_object->package.elements; + count = 1; + } + + /* Validate each sub-Package in the parent Package */ + for (i = 0; i < count; i++) { sub_package = *elements; sub_elements = sub_package->package.elements; diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index b64751eacc53..db2b2a99c3a8 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -149,3 +149,55 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, return (AE_AML_OPERAND_TYPE); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_repair_package_list + * + * PARAMETERS: Data - Pointer to validation data structure + * obj_desc_ptr - Pointer to the object to repair. The new + * package object is returned here, + * overwriting the old object. + * + * RETURN: Status, new object in *obj_desc_ptr + * + * DESCRIPTION: Repair a common problem with objects that are defined to return + * a variable-length Package of Packages. If the variable-length + * is one, some BIOS code mistakenly simply declares a single + * Package instead of a Package with one sub-Package. This + * function attempts to repair this error by wrapping a Package + * object around the original Package, creating the correct + * Package with one sub-Package. + * + * Names that can be repaired in this manner include: + * _ALR, _CSD, _HPX, _MLS, _PRT, _PSS, _TRT, TSS + * + ******************************************************************************/ + +acpi_status +acpi_ns_repair_package_list(struct acpi_predefined_data *data, + union acpi_operand_object **obj_desc_ptr) +{ + union acpi_operand_object *pkg_obj_desc; + + /* + * Create the new outer package and populate it. The new package will + * have a single element, the lone subpackage. + */ + pkg_obj_desc = acpi_ut_create_package_object(1); + if (!pkg_obj_desc) { + return (AE_NO_MEMORY); + } + + pkg_obj_desc->package.elements[0] = *obj_desc_ptr; + + /* Return the new object in the object pointer */ + + *obj_desc_ptr = pkg_obj_desc; + data->flags |= ACPI_OBJECT_REPAIRED; + + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Incorrectly formed Package, attempting repair")); + + return (AE_OK); +} -- cgit v1.2.3-59-g8ed1b From 53e9387bdd8bfef6cffff2d2eb6bd28eca812682 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 24 Jul 2009 11:22:11 +0800 Subject: ACPICA: ACPI 4.0 : Add new return package type, restructure module. Added one new package type, a package that contains a revision number and a variable number of sub-packages. Restructured the module to put the sub-package list traversal in a separate function. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acpredef.h | 5 +- drivers/acpi/acpica/nspredef.c | 326 ++++++++++++++++++++++++----------------- 2 files changed, 196 insertions(+), 135 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 63f656ae3604..144b1f41663f 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -91,6 +91,8 @@ * ACPI_PTYPE2_MIN: Each subpackage has a variable but minimum length * (Used for _HPX) * + * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length + * *****************************************************************************/ enum acpi_return_package_types { @@ -101,7 +103,8 @@ enum acpi_return_package_types { ACPI_PTYPE2_COUNT = 5, ACPI_PTYPE2_PKG_COUNT = 6, ACPI_PTYPE2_FIXED = 7, - ACPI_PTYPE2_MIN = 8 + ACPI_PTYPE2_MIN = 8, + ACPI_PTYPE2_REV_FIXED = 9 }; /* diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 0091504df074..0b2cdb37a678 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -75,6 +75,11 @@ static acpi_status acpi_ns_check_package(struct acpi_predefined_data *data, union acpi_operand_object **return_object_ptr); +static acpi_status +acpi_ns_check_package_list(struct acpi_predefined_data *data, + const union acpi_predefined_info *package, + union acpi_operand_object **elements, u32 count); + static acpi_status acpi_ns_check_package_elements(struct acpi_predefined_data *data, union acpi_operand_object **elements, @@ -393,14 +398,11 @@ acpi_ns_check_package(struct acpi_predefined_data *data, { union acpi_operand_object *return_object = *return_object_ptr; const union acpi_predefined_info *package; - union acpi_operand_object *sub_package; union acpi_operand_object **elements; - union acpi_operand_object **sub_elements; - acpi_status status; + acpi_status status = AE_OK; u32 expected_count; u32 count; u32 i; - u32 j; ACPI_FUNCTION_NAME(ns_check_package); @@ -465,9 +467,6 @@ acpi_ns_check_package(struct acpi_predefined_data *data, object_type2, package->ret_info. count2, 0); - if (ACPI_FAILURE(status)) { - return (status); - } break; case ACPI_PTYPE1_VAR: @@ -534,6 +533,25 @@ acpi_ns_check_package(struct acpi_predefined_data *data, } break; + case ACPI_PTYPE2_REV_FIXED: + + /* First element is the (Integer) revision */ + + status = acpi_ns_check_object_type(data, elements, + ACPI_RTYPE_INTEGER, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + + elements++; + count--; + + /* Examine the sub-packages */ + + status = + acpi_ns_check_package_list(data, package, elements, count); + break; + case ACPI_PTYPE2_PKG_COUNT: /* First element is the (Integer) count of sub-packages to follow */ @@ -556,9 +574,11 @@ acpi_ns_check_package(struct acpi_predefined_data *data, count = expected_count; elements++; - /* Now we can walk the sub-packages */ + /* Examine the sub-packages */ - /*lint -fallthrough */ + status = + acpi_ns_check_package_list(data, package, elements, count); + break; case ACPI_PTYPE2: case ACPI_PTYPE2_FIXED: @@ -593,175 +613,213 @@ acpi_ns_check_package(struct acpi_predefined_data *data, count = 1; } - /* Validate each sub-Package in the parent Package */ + /* Examine the sub-packages */ - for (i = 0; i < count; i++) { - sub_package = *elements; - sub_elements = sub_package->package.elements; + status = + acpi_ns_check_package_list(data, package, elements, count); + break; - /* Each sub-object must be of type Package */ + default: - status = acpi_ns_check_object_type(data, &sub_package, - ACPI_RTYPE_PACKAGE, - i); - if (ACPI_FAILURE(status)) { - return (status); - } + /* Should not get here if predefined info table is correct */ - /* Examine the different types of sub-packages */ + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Invalid internal return type in table entry: %X", + package->ret_info.type)); - switch (package->ret_info.type) { - case ACPI_PTYPE2: - case ACPI_PTYPE2_PKG_COUNT: + return (AE_AML_INTERNAL); + } - /* Each subpackage has a fixed number of elements */ + return (status); - expected_count = - package->ret_info.count1 + - package->ret_info.count2; - if (sub_package->package.count != - expected_count) { - count = sub_package->package.count; - goto package_too_small; - } +package_too_small: - status = - acpi_ns_check_package_elements(data, - sub_elements, - package-> - ret_info. - object_type1, - package-> - ret_info. - count1, - package-> - ret_info. - object_type2, - package-> - ret_info. - count2, 0); - if (ACPI_FAILURE(status)) { - return (status); - } - break; + /* Error exit for the case with an incorrect package count */ - case ACPI_PTYPE2_FIXED: + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Return Package is too small - found %u elements, expected %u", + count, expected_count)); - /* Each sub-package has a fixed length */ + return (AE_AML_OPERAND_VALUE); +} - expected_count = package->ret_info2.count; - if (sub_package->package.count < expected_count) { - count = sub_package->package.count; - goto package_too_small; - } +/******************************************************************************* + * + * FUNCTION: acpi_ns_check_package_list + * + * PARAMETERS: Data - Pointer to validation data structure + * Package - Pointer to package-specific info for method + * Elements - Element list of parent package. All elements + * of this list should be of type Package. + * Count - Count of subpackages + * + * RETURN: Status + * + * DESCRIPTION: Examine a list of subpackages + * + ******************************************************************************/ - /* Check the type of each sub-package element */ +static acpi_status +acpi_ns_check_package_list(struct acpi_predefined_data *data, + const union acpi_predefined_info *package, + union acpi_operand_object **elements, u32 count) +{ + union acpi_operand_object *sub_package; + union acpi_operand_object **sub_elements; + acpi_status status; + u32 expected_count; + u32 i; + u32 j; - for (j = 0; j < expected_count; j++) { - status = - acpi_ns_check_object_type(data, - &sub_elements[j], - package->ret_info2.object_type[j], j); - if (ACPI_FAILURE(status)) { - return (status); - } - } - break; + /* Validate each sub-Package in the parent Package */ - case ACPI_PTYPE2_MIN: + for (i = 0; i < count; i++) { + sub_package = *elements; + sub_elements = sub_package->package.elements; - /* Each sub-package has a variable but minimum length */ + /* Each sub-object must be of type Package */ - expected_count = package->ret_info.count1; - if (sub_package->package.count < expected_count) { - count = sub_package->package.count; - goto package_too_small; - } + status = acpi_ns_check_object_type(data, &sub_package, + ACPI_RTYPE_PACKAGE, i); + if (ACPI_FAILURE(status)) { + return (status); + } - /* Check the type of each sub-package element */ + /* Examine the different types of expected sub-packages */ - status = - acpi_ns_check_package_elements(data, - sub_elements, - package-> - ret_info. - object_type1, - sub_package-> - package. - count, 0, 0, - 0); - if (ACPI_FAILURE(status)) { - return (status); - } - break; + switch (package->ret_info.type) { + case ACPI_PTYPE2: + case ACPI_PTYPE2_PKG_COUNT: + case ACPI_PTYPE2_REV_FIXED: + + /* Each subpackage has a fixed number of elements */ + + expected_count = + package->ret_info.count1 + package->ret_info.count2; + if (sub_package->package.count < expected_count) { + goto package_too_small; + } + + status = + acpi_ns_check_package_elements(data, sub_elements, + package->ret_info. + object_type1, + package->ret_info. + count1, + package->ret_info. + object_type2, + package->ret_info. + count2, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + break; + + case ACPI_PTYPE2_FIXED: + + /* Each sub-package has a fixed length */ - case ACPI_PTYPE2_COUNT: + expected_count = package->ret_info2.count; + if (sub_package->package.count < expected_count) { + goto package_too_small; + } - /* First element is the (Integer) count of elements to follow */ + /* Check the type of each sub-package element */ + for (j = 0; j < expected_count; j++) { status = acpi_ns_check_object_type(data, - sub_elements, - ACPI_RTYPE_INTEGER, - 0); + &sub_elements[j], + package-> + ret_info2. + object_type[j], + j); if (ACPI_FAILURE(status)) { return (status); } + } + break; - /* Make sure package is large enough for the Count */ + case ACPI_PTYPE2_MIN: - expected_count = - (u32) (*sub_elements)->integer.value; - if (sub_package->package.count < expected_count) { - count = sub_package->package.count; - goto package_too_small; - } + /* Each sub-package has a variable but minimum length */ - /* Check the type of each sub-package element */ + expected_count = package->ret_info.count1; + if (sub_package->package.count < expected_count) { + goto package_too_small; + } - status = - acpi_ns_check_package_elements(data, - (sub_elements - + 1), - package-> - ret_info. - object_type1, - (expected_count - - 1), 0, 0, - 1); - if (ACPI_FAILURE(status)) { - return (status); - } - break; + /* Check the type of each sub-package element */ - default: - break; + status = + acpi_ns_check_package_elements(data, sub_elements, + package->ret_info. + object_type1, + sub_package->package. + count, 0, 0, 0); + if (ACPI_FAILURE(status)) { + return (status); } + break; - elements++; - } - break; + case ACPI_PTYPE2_COUNT: - default: + /* + * First element is the (Integer) count of elements, including + * the count field. + */ + status = acpi_ns_check_object_type(data, sub_elements, + ACPI_RTYPE_INTEGER, + 0); + if (ACPI_FAILURE(status)) { + return (status); + } - /* Should not get here if predefined info table is correct */ + /* + * Make sure package is large enough for the Count and is + * is as large as the minimum size + */ + expected_count = (u32)(*sub_elements)->integer.value; + if (sub_package->package.count < expected_count) { + goto package_too_small; + } + if (sub_package->package.count < + package->ret_info.count1) { + expected_count = package->ret_info.count1; + goto package_too_small; + } - ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, - "Invalid internal return type in table entry: %X", - package->ret_info.type)); + /* Check the type of each sub-package element */ - return (AE_AML_INTERNAL); + status = + acpi_ns_check_package_elements(data, + (sub_elements + 1), + package->ret_info. + object_type1, + (expected_count - 1), + 0, 0, 1); + if (ACPI_FAILURE(status)) { + return (status); + } + break; + + default: /* Should not get here, type was validated by caller */ + + return (AE_AML_INTERNAL); + } + + elements++; } return (AE_OK); - package_too_small: +package_too_small: - /* Error exit for the case with an incorrect package count */ + /* The sub-package count was smaller than required */ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, - "Return Package is too small - found %u, expected %u", - count, expected_count)); + "Return Sub-Package[%u] is too small - found %u elements, expected %u", + i, sub_package->package.count, expected_count)); return (AE_AML_OPERAND_VALUE); } -- cgit v1.2.3-59-g8ed1b From 2f977b36e5f175e5126f280e7a94f0c53d1b1a16 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 24 Jul 2009 11:25:16 +0800 Subject: ACPICA: Fix fault if acpi_terminate is called twice Fixes a problem with the mechanism that prevents problems if the acpi_terminate interface is inadvertently called more than once before the ACPICA code is re-initialized. ACPICA BZ 795. http://acpica.org/bugzilla/show_bug.cgi?id=795 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/utinit.c | 22 ++++------------------ drivers/acpi/acpica/utxface.c | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index a54ca84eb362..9d0919ebf7b0 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -99,33 +99,19 @@ static void acpi_ut_terminate(void) * * FUNCTION: acpi_ut_subsystem_shutdown * - * PARAMETERS: none + * PARAMETERS: None * - * RETURN: none + * RETURN: None * - * DESCRIPTION: Shutdown the various subsystems. Don't delete the mutex - * objects here -- because the AML debugger may be still running. + * DESCRIPTION: Shutdown the various components. Do not delete the mutex + * objects here, because the AML debugger may be still running. * ******************************************************************************/ void acpi_ut_subsystem_shutdown(void) { - ACPI_FUNCTION_TRACE(ut_subsystem_shutdown); - /* Just exit if subsystem is already shutdown */ - - if (acpi_gbl_shutdown) { - ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated")); - return_VOID; - } - - /* Subsystem appears active, go ahead and shut it down */ - - acpi_gbl_shutdown = TRUE; - acpi_gbl_startup_flags = 0; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n")); - #ifndef ACPI_ASL_COMPILER /* Close the acpi_event Handling */ diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 078a22728c6b..483edbb3f441 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -318,7 +318,7 @@ ACPI_EXPORT_SYMBOL(acpi_initialize_objects) * * RETURN: Status * - * DESCRIPTION: Shutdown the ACPI subsystem. Release all resources. + * DESCRIPTION: Shutdown the ACPICA subsystem and release all resources. * ******************************************************************************/ acpi_status acpi_terminate(void) @@ -327,6 +327,19 @@ acpi_status acpi_terminate(void) ACPI_FUNCTION_TRACE(acpi_terminate); + /* Just exit if subsystem is already shutdown */ + + if (acpi_gbl_shutdown) { + ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated")); + return_ACPI_STATUS(AE_OK); + } + + /* Subsystem appears active, go ahead and shut it down */ + + acpi_gbl_shutdown = TRUE; + acpi_gbl_startup_flags = 0; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n")); + /* Terminate the AML Debugger if present */ ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE); @@ -353,6 +366,7 @@ acpi_status acpi_terminate(void) } ACPI_EXPORT_SYMBOL(acpi_terminate) + #ifndef ACPI_ASL_COMPILER #ifdef ACPI_FUTURE_USAGE /******************************************************************************* -- cgit v1.2.3-59-g8ed1b From d9adc2e031bd22d5d9607a53a8d3b30e0b675f39 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 27 Jul 2009 11:31:10 +0800 Subject: ACPICA: reformat predefined method table, no functional change Reformatted the methods that return package objects. Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acpredef.h | 503 ++++++++++++++++++++++++----------------- 1 file changed, 293 insertions(+), 210 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 144b1f41663f..c81f14b69270 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -139,123 +139,180 @@ enum acpi_return_package_types { * is saved here (rather than in a separate table) in order to minimize the * overall size of the stored data. */ -static const union acpi_predefined_info predefined_names[] = { - {.info = {"_AC0", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC1", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC2", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC3", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC4", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC5", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC6", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC7", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC8", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AC9", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_ADR", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_AL0", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL1", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL2", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL3", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL4", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL5", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL6", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL7", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL8", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_AL9", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_ALC", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_ALI", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_ALP", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_ALR", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2, 0, 0, 0}}, /* variable (Pkgs) each 2 (Ints) */ - {.info = {"_ALT", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_BBN", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_BCL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */ - {.info = {"_BCM", 1, 0}}, - {.info = {"_BDN", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_BFS", 1, 0}}, - {.info = {"_BIF", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, - 9, - ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER, 4, 0}}, /* fixed (9 Int),(4 Str) */ - {.info = {"_BLT", 3, 0}}, - {.info = {"_BMC", 1, 0}}, - {.info = {"_BMD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* fixed (5 Int) */ - {.info = {"_BQC", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_BST", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */ - {.info = {"_BTM", 1, ACPI_RTYPE_INTEGER}}, - {.info = {"_BTP", 1, 0}}, - {.info = {"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* see PCI firmware spec 3.0 */ - {.info = {"_CID", 0, - ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, - {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0, 0, 0, 0}}, /* variable (Ints/Strs) */ - {.info = {"_CRS", 0, ACPI_RTYPE_BUFFER}}, - {.info = {"_CRT", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_CSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (1 Int(n), n-1 Int) */ - {.info = {"_CST", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_PKG_COUNT, - ACPI_RTYPE_BUFFER, 1, - ACPI_RTYPE_INTEGER, 3, 0}}, /* variable (1 Int(n), n Pkg (1 Buf/3 Int) */ - {.info = {"_DCK", 1, ACPI_RTYPE_INTEGER}}, - {.info = {"_DCS", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}}, - {.info = {"_DDN", 0, ACPI_RTYPE_STRING}}, - {.info = {"_DGS", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_DIS", 0, 0}}, - {.info = {"_DMA", 0, ACPI_RTYPE_BUFFER}}, - {.info = {"_DOD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */ - {.info = {"_DOS", 1, 0}}, - {.info = {"_DSM", 4, ACPI_RTYPE_ALL}}, /* Must return a type, but it can be of any type */ - {.info = {"_DSS", 1, 0}}, - {.info = {"_DSW", 3, 0}}, - {.info = {"_EC_", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_EDL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_EJ0", 1, 0}}, - {.info = {"_EJ1", 1, 0}}, - {.info = {"_EJ2", 1, 0}}, - {.info = {"_EJ3", 1, 0}}, - {.info = {"_EJ4", 1, 0}}, - {.info = {"_EJD", 0, ACPI_RTYPE_STRING}}, - {.info = {"_FDE", 0, ACPI_RTYPE_BUFFER}}, - {.info = {"_FDI", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, 0, 0, 0}}, /* fixed (16 Int) */ - {.info = {"_FDM", 1, 0}}, - {.info = {"_FIX", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */ - {.info = {"_GLK", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_GPD", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */ - {.info = {"_GSB", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_GTF", 0, ACPI_RTYPE_BUFFER}}, - {.info = {"_GTM", 0, ACPI_RTYPE_BUFFER}}, - {.info = {"_GTS", 1, 0}}, - {.info = {"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}}, - {.info = {"_HOT", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_HPP", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */ +static const union acpi_predefined_info predefined_names[] = +{ + {{"_AC0", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC1", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC2", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC3", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC4", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC5", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC6", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC7", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC8", 0, ACPI_RTYPE_INTEGER}}, + {{"_AC9", 0, ACPI_RTYPE_INTEGER}}, + {{"_ADR", 0, ACPI_RTYPE_INTEGER}}, + {{"_AL0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL1", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL2", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL3", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL4", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL5", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL6", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL7", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL8", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_AL9", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_ALC", 0, ACPI_RTYPE_INTEGER}}, + {{"_ALI", 0, ACPI_RTYPE_INTEGER}}, + {{"_ALP", 0, ACPI_RTYPE_INTEGER}}, + {{"_ALR", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 2 (Ints) */ + {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, + + {{"_ALT", 0, ACPI_RTYPE_INTEGER}}, + {{"_BBN", 0, ACPI_RTYPE_INTEGER}}, + {{"_BCL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}}, + + {{"_BCM", 1, 0}}, + {{"_BDN", 0, ACPI_RTYPE_INTEGER}}, + {{"_BFS", 1, 0}}, + {{"_BIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (9 Int),(4 Str) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, ACPI_RTYPE_STRING}, 4,0}}, + + {{"_BLT", 3, 0}}, + {{"_BMC", 1, 0}}, + {{"_BMD", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (5 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5,0}, 0,0}}, + + {{"_BQC", 0, ACPI_RTYPE_INTEGER}}, + {{"_BST", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}}, + + {{"_BTM", 1, ACPI_RTYPE_INTEGER}}, + {{"_BTP", 1, 0}}, + {{"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* See PCI firmware spec 3.0 */ + {{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0}, 0,0}}, + + {{"_CRS", 0, ACPI_RTYPE_BUFFER}}, + {{"_CRT", 0, ACPI_RTYPE_INTEGER}}, + {{"_CSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n-1 Int) */ + {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0}, 0,0}}, + + {{"_CST", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */ + {{{ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,0}}, + + {{"_DCK", 1, ACPI_RTYPE_INTEGER}}, + {{"_DCS", 0, ACPI_RTYPE_INTEGER}}, + {{"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}}, + {{"_DDN", 0, ACPI_RTYPE_STRING}}, + {{"_DGS", 0, ACPI_RTYPE_INTEGER}}, + {{"_DIS", 0, 0}}, + {{"_DMA", 0, ACPI_RTYPE_BUFFER}}, + {{"_DOD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}}, + + {{"_DOS", 1, 0}}, + {{"_DSM", 4, ACPI_RTYPE_ALL}}, /* Must return a type, but it can be of any type */ + {{"_DSS", 1, 0}}, + {{"_DSW", 3, 0}}, + {{"_EC_", 0, ACPI_RTYPE_INTEGER}}, + {{"_EDL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs)*/ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_EJ0", 1, 0}}, + {{"_EJ1", 1, 0}}, + {{"_EJ2", 1, 0}}, + {{"_EJ3", 1, 0}}, + {{"_EJ4", 1, 0}}, + {{"_EJD", 0, ACPI_RTYPE_STRING}}, + {{"_FDE", 0, ACPI_RTYPE_BUFFER}}, + {{"_FDI", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0}, 0,0}}, + + {{"_FDM", 1, 0}}, + {{"_FIX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}}, + + {{"_GLK", 0, ACPI_RTYPE_INTEGER}}, + {{"_GPD", 0, ACPI_RTYPE_INTEGER}}, + {{"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */ + {{"_GSB", 0, ACPI_RTYPE_INTEGER}}, + {{"_GTF", 0, ACPI_RTYPE_BUFFER}}, + {{"_GTM", 0, ACPI_RTYPE_BUFFER}}, + {{"_GTS", 1, 0}}, + {{"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}}, + {{"_HOT", 0, ACPI_RTYPE_INTEGER}}, + {{"_HPP", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}}, /* - * For _HPX, a single package is returned, containing a variable number of sub-packages. - * Each sub-package contains a PCI record setting. There are several different type of - * record settings, of different lengths, but all elements of all settings are Integers. + * For _HPX, a single package is returned, containing a Variable-length number + * of sub-packages. Each sub-package contains a PCI record setting. + * There are several different type of record settings, of different + * lengths, but all elements of all settings are Integers. */ - {.info = {"_HPX", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each (var Ints) */ - {.info = {"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* see IPMI spec */ - {.info = {"_INI", 0, 0}}, - {.info = {"_IRC", 0, 0}}, - {.info = {"_LCK", 1, 0}}, - {.info = {"_LID", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_MAT", 0, ACPI_RTYPE_BUFFER}}, - {.info = {"_MLS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_STRING, 2, 0, 0, 0}}, /* variable (Pkgs) each (2 Str) */ - {.info = {"_MSG", 1, 0}}, - {.info = {"_OFF", 0, 0}}, - {.info = {"_ON_", 0, 0}}, - {.info = {"_OS_", 0, ACPI_RTYPE_STRING}}, - {.info = {"_OSC", 4, ACPI_RTYPE_BUFFER}}, - {.info = {"_OST", 3, 0}}, - {.info = {"_PCL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_PCT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0}}, /* fixed (2 Buf) */ - {.info = {"_PDC", 1, 0}}, - {.info = {"_PIC", 1, 0}}, - {.info = {"_PLD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0, 0, 0, 0}}, /* variable (Bufs) */ - {.info = {"_PPC", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_PPE", 0, ACPI_RTYPE_INTEGER}}, /* see dig64 spec */ - {.info = {"_PR0", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_PR1", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_PR2", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_PRS", 0, ACPI_RTYPE_BUFFER}}, + {{"_HPX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (var Ints) */ + {{{ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5,0}, 0,0}}, + + {{"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */ + {{"_INI", 0, 0}}, + {{"_IRC", 0, 0}}, + {{"_LCK", 1, 0}}, + {{"_LID", 0, ACPI_RTYPE_INTEGER}}, + {{"_MAT", 0, ACPI_RTYPE_BUFFER}}, + {{"_MLS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (2 Str) */ + {{{ACPI_PTYPE2, ACPI_RTYPE_STRING, 2,0}, 0,0}}, + + {{"_MSG", 1, 0}}, + {{"_OFF", 0, 0}}, + {{"_ON_", 0, 0}}, + {{"_OS_", 0, ACPI_RTYPE_STRING}}, + {{"_OSC", 4, ACPI_RTYPE_BUFFER}}, + {{"_OST", 3, 0}}, + {{"_PCL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_PCT", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Buf) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0}, 0,0}}, + + {{"_PDC", 1, 0}}, + {{"_PIC", 1, 0}}, + {{"_PLD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Bufs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0,0}, 0,0}}, + + {{"_PPC", 0, ACPI_RTYPE_INTEGER}}, + {{"_PPE", 0, ACPI_RTYPE_INTEGER}}, /* See dig64 spec */ + {{"_PR0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_PR1", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_PR2", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_PRS", 0, ACPI_RTYPE_BUFFER}}, /* * For _PRT, many BIOSs reverse the 2nd and 3rd Package elements. This bug is so prevalent that there @@ -263,115 +320,141 @@ static const union acpi_predefined_info predefined_names[] = { * and issue a warning. To allow this and eliminate the warning, add the ACPI_RTYPE_REFERENCE * type to the 2nd element (index 1) in the statement below. */ - {.info = {"_PRT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_FIXED, 4, - ACPI_RTYPE_INTEGER, - ACPI_RTYPE_INTEGER, - ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE, ACPI_RTYPE_INTEGER}}, /* variable (Pkgs) each (4): Int,Int,Int/Ref,Int */ - - {.info = {"_PRW", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_OPTION, 2, - ACPI_RTYPE_INTEGER | - ACPI_RTYPE_PACKAGE, - ACPI_RTYPE_INTEGER, ACPI_RTYPE_REFERENCE, 0}}, /* variable (Pkgs) each: Pkg/Int,Int,[variable Refs] (Pkg is Ref/Int) */ - - {.info = {"_PS0", 0, 0}}, - {.info = {"_PS1", 0, 0}}, - {.info = {"_PS2", 0, 0}}, - {.info = {"_PS3", 0, 0}}, - {.info = {"_PSC", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_PSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Pkgs) each (5 Int) with count */ - {.info = {"_PSL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_PSR", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_PSS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6, 0, 0, 0}}, /* variable (Pkgs) each (6 Int) */ - {.info = {"_PSV", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_PSW", 1, 0}}, - {.info = {"_PTC", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0}}, /* fixed (2 Buf) */ - {.info = {"_PTS", 1, 0}}, - {.info = {"_PXM", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_REG", 2, 0}}, - {.info = {"_REV", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_RMV", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_ROM", 2, ACPI_RTYPE_BUFFER}}, - {.info = {"_RTV", 0, ACPI_RTYPE_INTEGER}}, + {{"_PRT", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (4): Int,Int,Int/Ref,Int */ + {{{ACPI_PTYPE2_FIXED, 4, ACPI_RTYPE_INTEGER,ACPI_RTYPE_INTEGER}, + ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE,ACPI_RTYPE_INTEGER}}, + + {{"_PRW", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each: Pkg/Int,Int,[Variable-length Refs] (Pkg is Ref/Int) */ + {{{ACPI_PTYPE1_OPTION, 2, ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE, + ACPI_RTYPE_INTEGER}, ACPI_RTYPE_REFERENCE,0}}, + + {{"_PS0", 0, 0}}, + {{"_PS1", 0, 0}}, + {{"_PS2", 0, 0}}, + {{"_PS3", 0, 0}}, + {{"_PSC", 0, ACPI_RTYPE_INTEGER}}, + {{"_PSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (5 Int) with count */ + {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER,0,0}, 0,0}}, + + {{"_PSL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_PSR", 0, ACPI_RTYPE_INTEGER}}, + {{"_PSS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (6 Int) */ + {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6,0}, 0,0}}, + + {{"_PSV", 0, ACPI_RTYPE_INTEGER}}, + {{"_PSW", 1, 0}}, + {{"_PTC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Buf) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0}, 0,0}}, + + {{"_PTS", 1, 0}}, + {{"_PXM", 0, ACPI_RTYPE_INTEGER}}, + {{"_REG", 2, 0}}, + {{"_REV", 0, ACPI_RTYPE_INTEGER}}, + {{"_RMV", 0, ACPI_RTYPE_INTEGER}}, + {{"_ROM", 2, ACPI_RTYPE_BUFFER}}, + {{"_RTV", 0, ACPI_RTYPE_INTEGER}}, /* - * For _S0_ through _S5_, the ACPI spec defines a return Package containing 1 Integer, - * but most DSDTs have it wrong - 2,3, or 4 integers. Allow this by making the objects "variable length", - * but all elements must be Integers. + * For _S0_ through _S5_, the ACPI spec defines a return Package + * containing 1 Integer, but most DSDTs have it wrong - 2,3, or 4 integers. + * Allow this by making the objects "Variable-length length", but all elements + * must be Integers. */ - {.info = {"_S0_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ - {.info = {"_S1_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ - {.info = {"_S2_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ - {.info = {"_S3_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ - {.info = {"_S4_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ - {.info = {"_S5_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ - - {.info = {"_S1D", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_S2D", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_S3D", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_S4D", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_S0W", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_S1W", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_S2W", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_S3W", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_S4W", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_SBS", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_SCP", 0x13, 0}}, /* Acpi 1.0 allowed 1 arg. Acpi 3.0 expanded to 3 args. Allow both. */ - /* Note: the 3-arg definition may be removed for ACPI 4.0 */ - {.info = {"_SDD", 1, 0}}, - {.info = {"_SEG", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_SLI", 0, ACPI_RTYPE_BUFFER}}, - {.info = {"_SPD", 1, ACPI_RTYPE_INTEGER}}, - {.info = {"_SRS", 1, 0}}, - {.info = {"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* see IPMI spec */ - {.info = {"_SST", 1, 0}}, - {.info = {"_STA", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_STM", 3, 0}}, - {.info = {"_STR", 0, ACPI_RTYPE_BUFFER}}, - {.info = {"_SUN", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_SWS", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_TC1", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_TC2", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_TMP", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_TPC", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_TPT", 1, 0}}, - {.info = {"_TRT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, - ACPI_RTYPE_INTEGER, 6, 0}}, /* variable (Pkgs) each 2_ref/6_int */ - {.info = {"_TSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each 5_int with count */ - {.info = {"_TSP", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_TSS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each 5_int */ - {.info = {"_TST", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_TTS", 1, 0}}, - {.info = {"_TZD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ - {.info = {"_TZM", 0, ACPI_RTYPE_REFERENCE}}, - {.info = {"_TZP", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_UID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}}, - {.info = {"_UPC", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */ - {.info = {"_UPD", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_UPP", 0, ACPI_RTYPE_INTEGER}}, - {.info = {"_VPO", 0, ACPI_RTYPE_INTEGER}}, + {{"_S0_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}}, + + {{"_S1_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}}, + + {{"_S2_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}}, + + {{"_S3_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}}, + + {{"_S4_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}}, + + {{"_S5_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}}, + + {{"_S1D", 0, ACPI_RTYPE_INTEGER}}, + {{"_S2D", 0, ACPI_RTYPE_INTEGER}}, + {{"_S3D", 0, ACPI_RTYPE_INTEGER}}, + {{"_S4D", 0, ACPI_RTYPE_INTEGER}}, + {{"_S0W", 0, ACPI_RTYPE_INTEGER}}, + {{"_S1W", 0, ACPI_RTYPE_INTEGER}}, + {{"_S2W", 0, ACPI_RTYPE_INTEGER}}, + {{"_S3W", 0, ACPI_RTYPE_INTEGER}}, + {{"_S4W", 0, ACPI_RTYPE_INTEGER}}, + {{"_SBS", 0, ACPI_RTYPE_INTEGER}}, + {{"_SCP", 0x13, 0}}, /* Acpi 1.0 allowed 1 arg. Acpi 3.0 expanded to 3 args. Allow both. */ + /* Note: the 3-arg definition may be removed for ACPI 4.0 */ + {{"_SDD", 1, 0}}, + {{"_SEG", 0, ACPI_RTYPE_INTEGER}}, + {{"_SLI", 0, ACPI_RTYPE_BUFFER}}, + {{"_SPD", 1, ACPI_RTYPE_INTEGER}}, + {{"_SRS", 1, 0}}, + {{"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */ + {{"_SST", 1, 0}}, + {{"_STA", 0, ACPI_RTYPE_INTEGER}}, + {{"_STM", 3, 0}}, + {{"_STR", 0, ACPI_RTYPE_BUFFER}}, + {{"_SUN", 0, ACPI_RTYPE_INTEGER}}, + {{"_SWS", 0, ACPI_RTYPE_INTEGER}}, + {{"_TC1", 0, ACPI_RTYPE_INTEGER}}, + {{"_TC2", 0, ACPI_RTYPE_INTEGER}}, + {{"_TMP", 0, ACPI_RTYPE_INTEGER}}, + {{"_TPC", 0, ACPI_RTYPE_INTEGER}}, + {{"_TPT", 1, 0}}, + {{"_TRT", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 2_ref/6_int */ + {{{ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER}, 6, 0}}, + + {{"_TSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 5_int with count */ + {{{ACPI_PTYPE2_COUNT,ACPI_RTYPE_INTEGER, 5,0}, 0,0}}, + + {{"_TSP", 0, ACPI_RTYPE_INTEGER}}, + {{"_TSS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 5_int */ + {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5,0}, 0,0}}, + + {{"_TST", 0, ACPI_RTYPE_INTEGER}}, + {{"_TTS", 1, 0}}, + {{"_TZD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + + {{"_TZM", 0, ACPI_RTYPE_REFERENCE}}, + {{"_TZP", 0, ACPI_RTYPE_INTEGER}}, + {{"_UID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}}, + {{"_UPC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}}, + + {{"_UPD", 0, ACPI_RTYPE_INTEGER}}, + {{"_UPP", 0, ACPI_RTYPE_INTEGER}}, + {{"_VPO", 0, ACPI_RTYPE_INTEGER}}, /* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */ - {.info = {"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}}, - {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0}}, /* fixed (2 Int), but is optional */ - {.ret_info = {0, 0, 0, 0, 0, 0}} /* Table terminator */ + {{"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}}, + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, /* Fixed-length (2 Int), but is optional */ + + {{{0,0,0,0}, 0,0}} /* Table terminator */ }; #if 0 /* Not implemented */ -{ -"_WDG", 0, ACPI_RTYPE_BUFFER}, /* MS Extension */ + {{"_WDG", 0, ACPI_RTYPE_BUFFER}}, /* MS Extension */ + {{"_WED", 1, ACPI_RTYPE_PACKAGE}}, /* MS Extension */ -{ -"_WED", 1, ACPI_RTYPE_PACKAGE}, /* MS Extension */ + /* This is an internally implemented control method, no need to check */ + {{"_OSI", 1, ACPI_RTYPE_INTEGER}}, - /* This is an internally implemented control method, no need to check */ -{ -"_OSI", 1, ACPI_RTYPE_INTEGER}, + /* TBD: */ - /* TBD: */ - _PRT - currently ignore reversed entries.attempt to fix here ? - think about code that attempts to fix package elements like _BIF, etc. + _PRT - currently ignore reversed entries. attempt to fix here? + think about possibly fixing package elements like _BIF, etc. #endif + #endif -- cgit v1.2.3-59-g8ed1b From 999e08f99846a1fd6ee9642ec306a2d318925116 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 13 Aug 2009 14:30:16 +0800 Subject: ACPICA: ACPI 4: Add validation for new predefined names. Added 31 new names for ACPI 4.0. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acpredef.h | 78 ++++++++++++++++++++++++++++++++++++++---- drivers/acpi/acpica/nspredef.c | 2 ++ 2 files changed, 73 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index c81f14b69270..cd80d1dd1950 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -64,8 +64,8 @@ * (Used for _PRW) * * - * 2) PTYPE2 packages contain a variable number of sub-packages. Each of the - * different types describe the contents of each of the sub-packages. + * 2) PTYPE2 packages contain a Variable-length number of sub-packages. Each + * of the different types describe the contents of each of the sub-packages. * * ACPI_PTYPE2: Each subpackage contains 1 or 2 object types: * object type @@ -92,6 +92,7 @@ * (Used for _HPX) * * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length + * (Used for _ART, _FPS) * *****************************************************************************/ @@ -107,6 +108,7 @@ enum acpi_return_package_types { ACPI_PTYPE2_REV_FIXED = 9 }; +#ifdef ACPI_CREATE_PREDEFINED_TABLE /* * Predefined method/object information table. * @@ -189,21 +191,32 @@ static const union acpi_predefined_info predefined_names[] = {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, {{"_ALT", 0, ACPI_RTYPE_INTEGER}}, + {{"_ART", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(rev), n Pkg (2 Ref/11 Int) */ + {{{ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER}, + 11, 0}}, + {{"_BBN", 0, ACPI_RTYPE_INTEGER}}, {{"_BCL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}}, {{"_BCM", 1, 0}}, + {{"_BCT", 1, ACPI_RTYPE_INTEGER}}, {{"_BDN", 0, ACPI_RTYPE_INTEGER}}, {{"_BFS", 1, 0}}, {{"_BIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (9 Int),(4 Str) */ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, ACPI_RTYPE_STRING}, 4,0}}, + {{"_BIX", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int),(4 Str) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, ACPI_RTYPE_STRING}, 4, + 0}}, + {{"_BLT", 3, 0}}, + {{"_BMA", 1, ACPI_RTYPE_INTEGER}}, {{"_BMC", 1, 0}}, {{"_BMD", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (5 Int) */ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5,0}, 0,0}}, + {{"_BMS", 1, ACPI_RTYPE_INTEGER}}, {{"_BQC", 0, ACPI_RTYPE_INTEGER}}, {{"_BST", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}}, @@ -211,6 +224,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_BTM", 1, ACPI_RTYPE_INTEGER}}, {{"_BTP", 1, 0}}, {{"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* See PCI firmware spec 3.0 */ + {{"_CDM", 0, ACPI_RTYPE_INTEGER}}, {{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0}, 0,0}}, @@ -236,6 +250,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_DSM", 4, ACPI_RTYPE_ALL}}, /* Must return a type, but it can be of any type */ {{"_DSS", 1, 0}}, {{"_DSW", 3, 0}}, + {{"_DTI", 1, 0}}, {{"_EC_", 0, ACPI_RTYPE_INTEGER}}, {{"_EDL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs)*/ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, @@ -251,9 +266,21 @@ static const union acpi_predefined_info predefined_names[] = {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0}, 0,0}}, {{"_FDM", 1, 0}}, + {{"_FIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0}, 0, 0}}, + {{"_FIX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}}, + {{"_FPS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(rev), n Pkg (5 Int) */ + {{{ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 5, 0}, 0, 0}}, + + {{"_FSL", 1, 0}}, + {{"_FST", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}}, + + {{"_GAI", 0, ACPI_RTYPE_INTEGER}}, + {{"_GHL", 0, ACPI_RTYPE_INTEGER}}, {{"_GLK", 0, ACPI_RTYPE_INTEGER}}, {{"_GPD", 0, ACPI_RTYPE_INTEGER}}, {{"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */ @@ -281,15 +308,21 @@ static const union acpi_predefined_info predefined_names[] = {{"_LCK", 1, 0}}, {{"_LID", 0, ACPI_RTYPE_INTEGER}}, {{"_MAT", 0, ACPI_RTYPE_BUFFER}}, + {{"_MBM", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (8 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8, 0}, 0, 0}}, + {{"_MLS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (2 Str) */ {{{ACPI_PTYPE2, ACPI_RTYPE_STRING, 2,0}, 0,0}}, {{"_MSG", 1, 0}}, + {{"_MSM", 4, ACPI_RTYPE_INTEGER}}, + {{"_NTT", 0, ACPI_RTYPE_INTEGER}}, {{"_OFF", 0, 0}}, {{"_ON_", 0, 0}}, {{"_OS_", 0, ACPI_RTYPE_STRING}}, {{"_OSC", 4, ACPI_RTYPE_BUFFER}}, {{"_OST", 3, 0}}, + {{"_PAI", 1, ACPI_RTYPE_INTEGER}}, {{"_PCL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, @@ -297,10 +330,22 @@ static const union acpi_predefined_info predefined_names[] = {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0}, 0,0}}, {{"_PDC", 1, 0}}, + {{"_PDL", 0, ACPI_RTYPE_INTEGER}}, {{"_PIC", 1, 0}}, + {{"_PIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int),(3 Str) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, ACPI_RTYPE_STRING}, 3, 0}}, + {{"_PLD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Bufs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0,0}, 0,0}}, + {{"_PMC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (11 Int),(3 Str) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 11, ACPI_RTYPE_STRING}, 3, + 0}}, + + {{"_PMD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + + {{"_PMM", 0, ACPI_RTYPE_INTEGER}}, {{"_PPC", 0, ACPI_RTYPE_INTEGER}}, {{"_PPE", 0, ACPI_RTYPE_INTEGER}}, /* See dig64 spec */ {{"_PR0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ @@ -312,17 +357,26 @@ static const union acpi_predefined_info predefined_names[] = {{"_PR2", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, + {{"_PR3", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + + {{"_PRL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + {{"_PRS", 0, ACPI_RTYPE_BUFFER}}, /* - * For _PRT, many BIOSs reverse the 2nd and 3rd Package elements. This bug is so prevalent that there - * is code in the ACPICA Resource Manager to detect this and switch them back. For now, do not allow - * and issue a warning. To allow this and eliminate the warning, add the ACPI_RTYPE_REFERENCE - * type to the 2nd element (index 1) in the statement below. + * For _PRT, many BIOSs reverse the 3rd and 4th Package elements (Source + * and source_index). This bug is so prevalent that there is code in the + * ACPICA Resource Manager to detect this and switch them back. For now, + * do not allow and issue a warning. To allow this and eliminate the + * warning, add the ACPI_RTYPE_REFERENCE type to the 4th element (index 3) + * in the statement below. */ {{"_PRT", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (4): Int,Int,Int/Ref,Int */ {{{ACPI_PTYPE2_FIXED, 4, ACPI_RTYPE_INTEGER,ACPI_RTYPE_INTEGER}, - ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE,ACPI_RTYPE_INTEGER}}, + ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE, + ACPI_RTYPE_INTEGER}}, {{"_PRW", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each: Pkg/Int,Int,[Variable-length Refs] (Pkg is Ref/Int) */ {{{ACPI_PTYPE1_OPTION, 2, ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE, @@ -348,7 +402,11 @@ static const union acpi_predefined_info predefined_names[] = {{"_PTC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Buf) */ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0}, 0,0}}, + {{"_PTP", 2, ACPI_RTYPE_INTEGER}}, {{"_PTS", 1, 0}}, + {{"_PUR", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0}, 0, 0}}, + {{"_PXM", 0, ACPI_RTYPE_INTEGER}}, {{"_REG", 2, 0}}, {{"_REV", 0, ACPI_RTYPE_INTEGER}}, @@ -394,6 +452,7 @@ static const union acpi_predefined_info predefined_names[] = /* Note: the 3-arg definition may be removed for ACPI 4.0 */ {{"_SDD", 1, 0}}, {{"_SEG", 0, ACPI_RTYPE_INTEGER}}, + {{"_SHL", 1, ACPI_RTYPE_INTEGER}}, {{"_SLI", 0, ACPI_RTYPE_BUFFER}}, {{"_SPD", 1, ACPI_RTYPE_INTEGER}}, {{"_SRS", 1, 0}}, @@ -401,11 +460,15 @@ static const union acpi_predefined_info predefined_names[] = {{"_SST", 1, 0}}, {{"_STA", 0, ACPI_RTYPE_INTEGER}}, {{"_STM", 3, 0}}, + {{"_STP", 2, ACPI_RTYPE_INTEGER}}, {{"_STR", 0, ACPI_RTYPE_BUFFER}}, + {{"_STV", 2, ACPI_RTYPE_INTEGER}}, {{"_SUN", 0, ACPI_RTYPE_INTEGER}}, {{"_SWS", 0, ACPI_RTYPE_INTEGER}}, {{"_TC1", 0, ACPI_RTYPE_INTEGER}}, {{"_TC2", 0, ACPI_RTYPE_INTEGER}}, + {{"_TIP", 1, ACPI_RTYPE_INTEGER}}, + {{"_TIV", 1, ACPI_RTYPE_INTEGER}}, {{"_TMP", 0, ACPI_RTYPE_INTEGER}}, {{"_TPC", 0, ACPI_RTYPE_INTEGER}}, {{"_TPT", 1, 0}}, @@ -458,3 +521,4 @@ static const union acpi_predefined_info predefined_names[] = #endif #endif +#endif diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 0b2cdb37a678..8314e6a9e726 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -42,6 +42,8 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#define ACPI_CREATE_PREDEFINED_TABLE + #include #include "accommon.h" #include "acnamesp.h" -- cgit v1.2.3-59-g8ed1b From 7f0c826a437157d2b19662977e9cf3b472cf24a6 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Thu, 13 Aug 2009 14:03:15 +0800 Subject: ACPICA: Add support for module-level executable AML code Add limited support for executable AML code that exists outside of any control method. This type of code has been illegal since ACPI 2.0. The code must exist in an If/Else/While block. All AML tables are supported, including tables that are dynamically loaded. ACPICA BZ 762. http://acpica.org/bugzilla/show_bug.cgi?id=762 Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/acpica/acglobal.h | 1 + drivers/acpi/acpica/acnamesp.h | 2 + drivers/acpi/acpica/acobject.h | 1 + drivers/acpi/acpica/acparser.h | 2 + drivers/acpi/acpica/dsfield.c | 18 ++++-- drivers/acpi/acpica/dsmethod.c | 15 +++-- drivers/acpi/acpica/dswload.c | 41 +++--------- drivers/acpi/acpica/exconfig.c | 7 +++ drivers/acpi/acpica/nseval.c | 137 +++++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/psloop.c | 119 ++++++++++++++++++++++++++++++++--- drivers/acpi/acpica/psxface.c | 4 ++ drivers/acpi/acpica/utglobal.c | 1 + drivers/acpi/acpica/utxface.c | 10 +++ 13 files changed, 306 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 6389f7c1de59..29ba66d5a790 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -295,6 +295,7 @@ extern char const *acpi_gbl_exception_names_ctrl[]; ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct; ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node; ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device; +ACPI_EXTERN union acpi_operand_object *acpi_gbl_module_code_list; extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES]; extern const struct acpi_predefined_names diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index f75a7a01b875..09a2764c734b 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -196,6 +196,8 @@ acpi_ns_dump_objects(acpi_object_type type, */ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info); +void acpi_ns_exec_module_code_list(void); + /* * nspredef - Support for predefined/reserved names */ diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index eb6f038b03d9..b39d682a2140 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -98,6 +98,7 @@ #define AOPOBJ_SETUP_COMPLETE 0x10 #define AOPOBJ_SINGLE_DATUM 0x20 #define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */ +#define AOPOBJ_MODULE_LEVEL 0x80 /****************************************************************************** * diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 23ee0fbf5619..22881e8ce229 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -62,6 +62,8 @@ #define ACPI_PARSE_DEFERRED_OP 0x0100 #define ACPI_PARSE_DISASSEMBLE 0x0200 +#define ACPI_PARSE_MODULE_LEVEL 0x0400 + /****************************************************************************** * * Parser interfaces diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 53e27bc5a734..54a225e56a64 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -123,9 +123,12 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND; - /* Mark node temporary if we are executing a method */ - - if (walk_state->method_node) { + /* + * Mark node temporary if we are executing a normal control + * method. (Don't mark if this is a module-level code method) + */ + if (walk_state->method_node && + !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) { flags |= ACPI_NS_TEMPORARY; } @@ -456,9 +459,12 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND; - /* Mark node(s) temporary if we are executing a method */ - - if (walk_state->method_node) { + /* + * Mark node(s) temporary if we are executing a normal control + * method. (Don't mark if this is a module-level code method) + */ + if (walk_state->method_node && + !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) { flags |= ACPI_NS_TEMPORARY; } diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 14b8b8ed8023..567a4899a018 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -578,10 +578,15 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, } /* - * Delete any namespace objects created anywhere within - * the namespace by the execution of this method + * Delete any namespace objects created anywhere within the + * namespace by the execution of this method. Unless this method + * is a module-level executable code method, in which case we + * want make the objects permanent. */ - acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id); + if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) { + acpi_ns_delete_namespace_by_owner(method_desc->method. + owner_id); + } } /* Decrement the thread count on the method */ @@ -622,7 +627,9 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, /* No more threads, we can free the owner_id */ - acpi_ut_release_owner_id(&method_desc->method.owner_id); + if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) { + acpi_ut_release_owner_id(&method_desc->method.owner_id); + } } return_VOID; diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 3023ceaa8d54..6de3a99d4cd4 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -581,21 +581,6 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) || (!(walk_state->op_info->flags & AML_NAMED))) { -#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE - if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || - (walk_state->op_info->class == AML_CLASS_CONTROL)) { - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Begin/EXEC: %s (fl %8.8X)\n", - walk_state->op_info->name, - walk_state->op_info->flags)); - - /* Executing a type1 or type2 opcode outside of a method */ - - status = - acpi_ds_exec_begin_op(walk_state, out_op); - return_ACPI_STATUS(status); - } -#endif return_ACPI_STATUS(AE_OK); } @@ -768,7 +753,13 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, /* Execution mode, node cannot already exist, node is temporary */ - flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY); + flags |= ACPI_NS_ERROR_IF_FOUND; + + if (! + (walk_state-> + parse_flags & ACPI_PARSE_MODULE_LEVEL)) { + flags |= ACPI_NS_TEMPORARY; + } } /* Add new entry or lookup existing entry */ @@ -851,24 +842,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) /* Check if opcode had an associated namespace object */ if (!(walk_state->op_info->flags & AML_NSOBJECT)) { -#ifndef ACPI_NO_METHOD_EXECUTION -#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE - /* No namespace object. Executable opcode? */ - - if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || - (walk_state->op_info->class == AML_CLASS_CONTROL)) { - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "End/EXEC: %s (fl %8.8X)\n", - walk_state->op_info->name, - walk_state->op_info->flags)); - - /* Executing a type1 or type2 opcode outside of a method */ - - status = acpi_ds_exec_end_op(walk_state); - return_ACPI_STATUS(status); - } -#endif -#endif return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 277fd609611a..24afef81af39 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -110,8 +110,15 @@ acpi_ex_add_table(u32 table_index, if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(obj_desc); *ddb_handle = NULL; + return_ACPI_STATUS(status); } + /* Execute any module-level code that was found in the table */ + + acpi_ex_exit_interpreter(); + acpi_ns_exec_module_code_list(); + acpi_ex_enter_interpreter(); + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index 8e7dec1176c9..846d1132feb1 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -50,6 +50,11 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nseval") +/* Local prototypes */ +static void +acpi_ns_exec_module_code(union acpi_operand_object *method_obj, + struct acpi_evaluate_info *info); + /******************************************************************************* * * FUNCTION: acpi_ns_evaluate @@ -76,6 +81,7 @@ ACPI_MODULE_NAME("nseval") * MUTEX: Locks interpreter * ******************************************************************************/ + acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) { acpi_status status; @@ -276,3 +282,134 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) */ return_ACPI_STATUS(status); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_exec_module_code_list + * + * PARAMETERS: None + * + * RETURN: None. Exceptions during method execution are ignored, since + * we cannot abort a table load. + * + * DESCRIPTION: Execute all elements of the global module-level code list. + * Each element is executed as a single control method. + * + ******************************************************************************/ + +void acpi_ns_exec_module_code_list(void) +{ + union acpi_operand_object *prev; + union acpi_operand_object *next; + struct acpi_evaluate_info *info; + u32 method_count = 0; + + ACPI_FUNCTION_TRACE(ns_exec_module_code_list); + + /* Exit now if the list is empty */ + + next = acpi_gbl_module_code_list; + if (!next) { + return_VOID; + } + + /* Allocate the evaluation information block */ + + info = ACPI_ALLOCATE(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_VOID; + } + + /* Walk the list, executing each "method" */ + + while (next) { + prev = next; + next = next->method.mutex; + + /* Clear the link field and execute the method */ + + prev->method.mutex = NULL; + acpi_ns_exec_module_code(prev, info); + method_count++; + + /* Delete the (temporary) method object */ + + acpi_ut_remove_reference(prev); + } + + ACPI_INFO((AE_INFO, + "Executed %u blocks of module-level executable AML code", + method_count)); + + ACPI_FREE(info); + acpi_gbl_module_code_list = NULL; + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_exec_module_code + * + * PARAMETERS: method_obj - Object container for the module-level code + * Info - Info block for method evaluation + * + * RETURN: None. Exceptions during method execution are ignored, since + * we cannot abort a table load. + * + * DESCRIPTION: Execute a control method containing a block of module-level + * executable AML code. The control method is temporarily + * installed to the root node, then evaluated. + * + ******************************************************************************/ + +static void +acpi_ns_exec_module_code(union acpi_operand_object *method_obj, + struct acpi_evaluate_info *info) +{ + union acpi_operand_object *root_obj; + acpi_status status; + + ACPI_FUNCTION_TRACE(ns_exec_module_code); + + /* Initialize the evaluation information block */ + + ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info)); + info->prefix_node = acpi_gbl_root_node; + + /* + * Get the currently attached root object. Add a reference, because the + * ref count will be decreased when the method object is installed to + * the root node. + */ + root_obj = acpi_ns_get_attached_object(acpi_gbl_root_node); + acpi_ut_add_reference(root_obj); + + /* Install the method (module-level code) in the root node */ + + status = acpi_ns_attach_object(acpi_gbl_root_node, method_obj, + ACPI_TYPE_METHOD); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* Execute the root node as a control method */ + + status = acpi_ns_evaluate(info); + + ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n", + method_obj->method.aml_start)); + + /* Detach the temporary method object */ + + acpi_ns_detach_object(acpi_gbl_root_node); + + /* Restore the original root object */ + + status = + acpi_ns_attach_object(acpi_gbl_root_node, root_obj, + ACPI_TYPE_DEVICE); + + exit: + acpi_ut_remove_reference(root_obj); + return_VOID; +} diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index c5f6ce19a401..cd7995b3aed4 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -86,6 +86,9 @@ static acpi_status acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, union acpi_parse_object *op, acpi_status status); +static void +acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id); + /******************************************************************************* * * FUNCTION: acpi_ps_get_aml_opcode @@ -390,6 +393,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, { acpi_status status = AE_OK; union acpi_parse_object *arg = NULL; + const struct acpi_opcode_info *op_info; ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); @@ -449,13 +453,11 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, INCREMENT_ARG_LIST(walk_state->arg_types); } - /* Special processing for certain opcodes */ - - /* TBD (remove): Temporary mechanism to disable this code if needed */ - -#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE - - if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) && + /* + * Handle executable code at "module-level". This refers to + * executable opcodes that appear outside of any control method. + */ + if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) && ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { /* * We want to skip If/Else/While constructs during Pass1 because we @@ -469,6 +471,23 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, case AML_ELSE_OP: case AML_WHILE_OP: + /* + * Currently supported module-level opcodes are: + * IF/ELSE/WHILE. These appear to be the most common, + * and easiest to support since they open an AML + * package. + */ + if (walk_state->pass_number == + ACPI_IMODE_LOAD_PASS1) { + acpi_ps_link_module_code(aml_op_start, + walk_state-> + parser_state. + pkg_end - + aml_op_start, + walk_state-> + owner_id); + } + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Pass1: Skipping an If/Else/While body\n")); @@ -480,10 +499,34 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, break; default: + /* + * Check for an unsupported executable opcode at module + * level. We must be in PASS1, the parent must be a SCOPE, + * The opcode class must be EXECUTE, and the opcode must + * not be an argument to another opcode. + */ + if ((walk_state->pass_number == + ACPI_IMODE_LOAD_PASS1) + && (op->common.parent->common.aml_opcode == + AML_SCOPE_OP)) { + op_info = + acpi_ps_get_opcode_info(op->common. + aml_opcode); + if ((op_info->class == + AML_CLASS_EXECUTE) && (!arg)) { + ACPI_WARNING((AE_INFO, + "Detected an unsupported executable opcode " + "at module-level: [0x%.4X] at table offset 0x%.4X", + op->common.aml_opcode, + (u32)((aml_op_start - walk_state->parser_state.aml_start) + + sizeof(struct acpi_table_header)))); + } + } break; } } -#endif + + /* Special processing for certain opcodes */ switch (op->common.aml_opcode) { case AML_METHOD_OP: @@ -551,6 +594,66 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_OK); } +/******************************************************************************* + * + * FUNCTION: acpi_ps_link_module_code + * + * PARAMETERS: aml_start - Pointer to the AML + * aml_length - Length of executable AML + * owner_id - owner_id of module level code + * + * RETURN: None. + * + * DESCRIPTION: Wrap the module-level code with a method object and link the + * object to the global list. Note, the mutex field of the method + * object is used to link multiple module-level code objects. + * + ******************************************************************************/ + +static void +acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id) +{ + union acpi_operand_object *prev; + union acpi_operand_object *next; + union acpi_operand_object *method_obj; + + /* Get the tail of the list */ + + prev = next = acpi_gbl_module_code_list; + while (next) { + prev = next; + next = next->method.mutex; + } + + /* + * Insert the module level code into the list. Merge it if it is + * adjacent to the previous element. + */ + if (!prev || + ((prev->method.aml_start + prev->method.aml_length) != aml_start)) { + + /* Create, initialize, and link a new temporary method object */ + + method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); + if (!method_obj) { + return; + } + + method_obj->method.aml_start = aml_start; + method_obj->method.aml_length = aml_length; + method_obj->method.owner_id = owner_id; + method_obj->method.flags |= AOPOBJ_MODULE_LEVEL; + + if (!prev) { + acpi_gbl_module_code_list = method_obj; + } else { + prev->method.mutex = method_obj; + } + } else { + prev->method.aml_length += aml_length; + } +} + /******************************************************************************* * * FUNCTION: acpi_ps_complete_op diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index ff06032c0f06..dd9731c29a79 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -280,6 +280,10 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) goto cleanup; } + if (info->obj_desc->method.flags & AOPOBJ_MODULE_LEVEL) { + walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; + } + /* Invoke an internal method if necessary */ if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 9e33b6261939..3f2c68f4e959 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -807,6 +807,7 @@ acpi_status acpi_ut_init_globals(void) /* Namespace */ + acpi_gbl_module_code_list = NULL; acpi_gbl_root_node = NULL; acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME; acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED; diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 483edbb3f441..b1f5f680bc78 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -250,6 +250,16 @@ acpi_status acpi_initialize_objects(u32 flags) } } + /* + * Execute any module-level code that was detected during the table load + * phase. Although illegal since ACPI 2.0, there are many machines that + * contain this type of code. Each block of detected executable AML code + * outside of any control method is wrapped with a temporary control + * method object and placed on a global list. The methods on this list + * are executed below. + */ + acpi_ns_exec_module_code_list(); + /* * Initialize the objects that remain uninitialized. This runs the * executable AML that may be part of the declaration of these objects: -- cgit v1.2.3-59-g8ed1b From 8a964236800839263b3dddd7f7851d666e7d53e1 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 13 Aug 2009 13:42:19 +0800 Subject: ACPICA: acpi_reset: Bypass port validation mechanism Allow writes to reserved ports. This change may eventually be driven down in to acpi_write and acpi_read. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/hwxface.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 4ead85f29215..647c7b6e6756 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -78,9 +78,22 @@ acpi_status acpi_reset(void) return_ACPI_STATUS(AE_NOT_EXIST); } - /* Write the reset value to the reset register */ + if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + /* + * For I/O space, write directly to the OSL. This bypasses the port + * validation mechanism, which may block a valid write to the reset + * register. + */ + status = + acpi_os_write_port((acpi_io_address) reset_reg->address, + acpi_gbl_FADT.reset_value, + reset_reg->bit_width); + } else { + /* Write the reset value to the reset register */ + + status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg); + } - status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg); return_ACPI_STATUS(status); } -- cgit v1.2.3-59-g8ed1b From a192a9580bcc41692be1f36b77c3b681827f566a Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 28 Jul 2009 16:45:54 -0400 Subject: ACPI: Move definition of PREFIX from acpi_bus.h to internal..h Linux/ACPI core files using internal.h all PREFIX "ACPI: ", however, not all ACPI drivers use/want it -- and they should not have to #undef PREFIX to define their own. Add GPL commment to internal.h while we are there. This does not change any actual console output, asside from a whitespace fix. Signed-off-by: Len Brown --- arch/x86/pci/mmconfig-shared.c | 2 ++ drivers/acpi/ac.c | 2 ++ drivers/acpi/battery.c | 2 ++ drivers/acpi/blacklist.c | 2 ++ drivers/acpi/button.c | 2 ++ drivers/acpi/cm_sbs.c | 2 ++ drivers/acpi/container.c | 2 ++ drivers/acpi/dock.c | 2 ++ drivers/acpi/ec.c | 1 - drivers/acpi/event.c | 2 ++ drivers/acpi/fan.c | 2 ++ drivers/acpi/glue.c | 2 ++ drivers/acpi/internal.h | 22 +++++++++++++++++++++- drivers/acpi/numa.c | 2 ++ drivers/acpi/pci_irq.c | 2 ++ drivers/acpi/pci_link.c | 2 ++ drivers/acpi/pci_root.c | 2 ++ drivers/acpi/power.c | 2 ++ drivers/acpi/processor_core.c | 2 ++ drivers/acpi/processor_idle.c | 2 ++ drivers/acpi/processor_perflib.c | 2 ++ drivers/acpi/processor_thermal.c | 2 ++ drivers/acpi/processor_throttling.c | 2 ++ drivers/acpi/sbs.c | 2 ++ drivers/acpi/sbshc.c | 2 ++ drivers/acpi/system.c | 2 ++ drivers/acpi/thermal.c | 2 ++ drivers/acpi/utils.c | 2 ++ drivers/acpi/video.c | 2 ++ drivers/acpi/video_detect.c | 2 ++ drivers/pci/dmar.c | 3 +-- drivers/platform/x86/fujitsu-laptop.c | 4 ++-- drivers/platform/x86/wmi.c | 1 - include/acpi/acpi_bus.h | 2 -- 34 files changed, 80 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 712443ec6d43..81d3466765ca 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -18,6 +18,8 @@ #include #include +#define PREFIX "ACPI: " + /* aperture is up to 256MB but BIOS may reserve less */ #define MMCONFIG_APER_MIN (2 * 1024*1024) #define MMCONFIG_APER_MAX (256 * 1024*1024) diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 0df8fcb687d6..98b9690b0159 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -37,6 +37,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_AC_CLASS "ac_adapter" #define ACPI_AC_DEVICE_NAME "AC Adapter" #define ACPI_AC_FILE_STATE "state" diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 58b4517ce712..f8c3d1bb6969 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -45,6 +45,8 @@ #include #endif +#define PREFIX "ACPI: " + #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF #define ACPI_BATTERY_CLASS "battery" diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index f6baa77deefb..19152ea2b104 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -34,6 +34,8 @@ #include #include +#include "internal.h" + enum acpi_blacklist_predicates { all_versions, less_than_or_equal, diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 9195deba9d94..d295bdccc09c 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -33,6 +33,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_BUTTON_CLASS "button" #define ACPI_BUTTON_FILE_INFO "info" #define ACPI_BUTTON_FILE_STATE "state" diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 332fe4b21708..6c9ee68e46fb 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -28,6 +28,8 @@ #include #include +#define PREFIX "ACPI: " + ACPI_MODULE_NAME("cm_sbs"); #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index fe0cdf83641a..5f2c3c00a315 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -35,6 +35,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_CONTAINER_DEVICE_NAME "ACPI container device" #define ACPI_CONTAINER_CLASS "container" diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index efb959d6c8a9..9a855669ff12 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -33,6 +33,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" ACPI_MODULE_NAME("dock"); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 391f331674c7..5180f0f1dd02 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -47,7 +47,6 @@ #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" -#undef PREFIX #define PREFIX "ACPI: EC: " /* EC status register */ diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index aeb7e5fb4a04..c511071bfd79 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -14,6 +14,8 @@ #include #include +#include "internal.h" + #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("event"); diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 53698ea08371..f419849a0d3f 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -34,6 +34,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_FAN_CLASS "fan" #define ACPI_FAN_FILE_STATE "state" diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index a8a5c29958c8..dc36a448de43 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -12,6 +12,8 @@ #include #include +#include "internal.h" + #define ACPI_GLUE_DEBUG 0 #if ACPI_GLUE_DEBUG #define DBG(x...) printk(PREFIX x) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 11a69b53004e..074cf8682d52 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -1,4 +1,24 @@ -/* For use by Linux/ACPI infrastructure, not drivers */ +/* + * acpi/internal.h + * For use by Linux/ACPI infrastructure, not drivers + * + * Copyright (c) 2009, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define PREFIX "ACPI: " int init_acpi_device_notify(void); int acpi_scan_init(void); diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index d440ccd27d91..202dd0c976a3 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -30,6 +30,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_NUMA 0x80000000 #define _COMPONENT ACPI_NUMA ACPI_MODULE_NAME("numa"); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index b794eb88ab90..843699ed93f2 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -40,6 +40,8 @@ #include #include +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_irq"); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 16e0f9d3d17c..394ae89409c2 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -43,6 +43,8 @@ #include #include +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_link"); #define ACPI_PCI_LINK_CLASS "pci_irq_routing" diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 55b5b90c2a44..dee916707a7d 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -36,6 +36,8 @@ #include #include +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_root"); #define ACPI_PCI_ROOT_CLASS "pci_bridge" diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index d74365d4a6e7..e86603f37dee 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -44,6 +44,8 @@ #include #include +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_POWER_COMPONENT ACPI_MODULE_NAME("power"); #define ACPI_POWER_CLASS "power_resource" diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 2cc4b3033872..b4a1ab297e7b 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -59,6 +59,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define ACPI_PROCESSOR_DEVICE_NAME "Processor" #define ACPI_PROCESSOR_FILE_INFO "info" diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 66393d5c4c7c..22aab1fc9b45 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -60,6 +60,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_idle"); diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 60e543d3234e..11088cf10319 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -39,6 +39,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define _COMPONENT ACPI_PROCESSOR_COMPONENT diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 31adda1099e0..3e3181c0efc3 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -40,6 +40,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_thermal"); diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index ae39797aab55..b366b9c13d4d 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -41,6 +41,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_throttling"); diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 4b214b74ebaa..52b9db8afc20 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -46,6 +46,8 @@ #include "sbshc.h" +#define PREFIX "ACPI: " + #define ACPI_SBS_CLASS "sbs" #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 0619734895b2..d9339806df45 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -15,6 +15,8 @@ #include #include "sbshc.h" +#define PREFIX "ACPI: " + #define ACPI_SMB_HC_CLASS "smbus_host_controller" #define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC" diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 9c61ab2177cf..d11282975f35 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -31,6 +31,8 @@ #include +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("system"); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 564ea1424288..65f67815902a 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -47,6 +47,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_THERMAL_CLASS "thermal_zone" #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" #define ACPI_THERMAL_FILE_STATE "state" diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index f844941089bb..811fec10462b 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -30,6 +30,8 @@ #include #include +#include "internal.h" + #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("utils"); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 8851315ce858..a0fa3946b507 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -44,6 +44,8 @@ #include #include +#define PREFIX "ACPI: " + #define ACPI_VIDEO_CLASS "video" #define ACPI_VIDEO_BUS_NAME "Video Bus" #define ACPI_VIDEO_DEVICE_NAME "Video Device" diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 7cd2b63435ea..7032f25da9b5 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -38,6 +38,8 @@ #include #include +#define PREFIX "ACPI: " + ACPI_MODULE_NAME("video"); #define _COMPONENT ACPI_VIDEO_COMPONENT diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 7b287cb38b7a..998f02d2ba42 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -34,8 +34,7 @@ #include #include -#undef PREFIX -#define PREFIX "DMAR:" +#define PREFIX "DMAR: " /* No locks are needed as DMA remapping hardware unit * list is constructed at boot time and hotplug of diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 218b9a16ac3f..eabddc9c192b 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -700,7 +700,7 @@ static int acpi_fujitsu_add(struct acpi_device *device) goto end; } - printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + printk(KERN_INFO "ACPI: %s [%s] (%s)\n", acpi_device_name(device), acpi_device_bid(device), !device->power.state ? "on" : "off"); @@ -874,7 +874,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) goto end; } - printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + printk(KERN_INFO "ACPI: %s [%s] (%s)\n", acpi_device_name(device), acpi_device_bid(device), !device->power.state ? "on" : "off"); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index f215a5919192..177f8d767df4 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -42,7 +42,6 @@ MODULE_LICENSE("GPL"); #define ACPI_WMI_CLASS "wmi" -#undef PREFIX #define PREFIX "ACPI: WMI: " static DEFINE_MUTEX(wmi_data_lock); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c65e4ce6c3af..f485107ddc43 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -30,8 +30,6 @@ #include -#define PREFIX "ACPI: " - /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 struct acpi_handle_list { -- cgit v1.2.3-59-g8ed1b From e5b8fc6ac158f65598f58dba2c0d52ba3b412f52 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 7 Jul 2009 23:22:58 -0400 Subject: ACPI: check acpi_disabled in acpi_table_parse() and acpi_table_parse_entries() Allow consumers of the acpi_table_parse()/acpi_table_parse_entries() API to gracefully handle the acpi_disabled=1 case via return value rather than checking the global flag themselves. Signed-off-by: Feng Tang Signed-off-by: Len Brown --- drivers/acpi/tables.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 646d39c031ca..f336bca7c450 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -213,6 +213,9 @@ acpi_table_parse_entries(char *id, unsigned long table_end; acpi_size tbl_size; + if (acpi_disabled) + return -ENODEV; + if (!handler) return -EINVAL; @@ -277,6 +280,9 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler) struct acpi_table_header *table = NULL; acpi_size tbl_size; + if (acpi_disabled) + return -ENODEV; + if (!handler) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From be96666065fd36ccfa09a13903d31d7ff5f4ef91 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 29 Aug 2009 10:28:29 +0200 Subject: asus-laptop: Fix coding style for comments Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 108 +++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 5b912cc5cbee..b39d2bb3e75b 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -77,16 +77,16 @@ * Flags for hotk status * WL_ON and BT_ON are also used for wireless_status() */ -#define WL_ON 0x01 //internal Wifi -#define BT_ON 0x02 //internal Bluetooth -#define MLED_ON 0x04 //mail LED -#define TLED_ON 0x08 //touchpad LED -#define RLED_ON 0x10 //Record LED -#define PLED_ON 0x20 //Phone LED -#define GLED_ON 0x40 //Gaming LED -#define LCD_ON 0x80 //LCD backlight -#define GPS_ON 0x100 //GPS -#define KEY_ON 0x200 //Keyboard backlight +#define WL_ON 0x01 /* internal Wifi */ +#define BT_ON 0x02 /* internal Bluetooth */ +#define MLED_ON 0x04 /* mail LED */ +#define TLED_ON 0x08 /* touchpad LED */ +#define RLED_ON 0x10 /* Record LED */ +#define PLED_ON 0x20 /* Phone LED */ +#define GLED_ON 0x40 /* Gaming LED */ +#define LCD_ON 0x80 /* LCD backlight */ +#define GPS_ON 0x100 /* GPS */ +#define KEY_ON 0x200 /* Keyboard backlight */ #define ASUS_LOG ASUS_HOTK_FILE ": " #define ASUS_ERR KERN_ERR ASUS_LOG @@ -99,7 +99,8 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); MODULE_DESCRIPTION(ASUS_HOTK_NAME); MODULE_LICENSE("GPL"); -/* WAPF defines the behavior of the Fn+Fx wlan key +/* + * WAPF defines the behavior of the Fn+Fx wlan key * The significance of values is yet to be found, but * most of the time: * 0x0 will do nothing @@ -126,7 +127,8 @@ ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */ /* LEDD */ ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); -/* Bluetooth and WLAN +/* + * Bluetooth and WLAN * WLED and BLED are not handled like other XLED, because in some dsdt * they also control the WLAN/Bluetooth device. */ @@ -150,22 +152,32 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ /* Display */ ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); -ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G - M6A M6V VX-1 V6J V6V W3Z */ - "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V - S5A M5A z33A W1Jc W2V G1 */ - "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ - "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ - "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ - "\\_SB.PCI0.VGA.GETD", /* Z96F */ - "\\ACTD", /* A2D */ - "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ - "\\DNXT", /* P30 */ - "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ - "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ - -ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ -ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ +ASUS_HANDLE(display_get, + /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ + "\\_SB.PCI0.P0P1.VGA.GETD", + /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ + "\\_SB.PCI0.P0P2.VGA.GETD", + /* A6V A6Q */ + "\\_SB.PCI0.P0P3.VGA.GETD", + /* A6T, A6M */ + "\\_SB.PCI0.P0PA.VGA.GETD", + /* L3C */ + "\\_SB.PCI0.PCI1.VGAC.NMAP", + /* Z96F */ + "\\_SB.PCI0.VGA.GETD", + /* A2D */ + "\\ACTD", + /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ + "\\ADVG", + /* P30 */ + "\\DNXT", + /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ + "\\INFB", + /* A3F A6F A3N A3L M6N W3N W6A */ + "\\SSTE"); + +ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ +ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ /* GPS */ /* R2H use different handle for GPS on/off */ @@ -182,14 +194,14 @@ ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB"); * about the hotk device */ struct asus_hotk { - char *name; //laptop name - struct acpi_device *device; //the device we are in - acpi_handle handle; //the handle of the hotk device - char status; //status of the hotk, for LEDs, ... - u32 ledd_status; //status of the LED display - u8 light_level; //light sensor level - u8 light_switch; //light sensor switch value - u16 event_count[128]; //count for each event TODO make this better + char *name; /* laptop name */ + struct acpi_device *device; /* the device we are in */ + acpi_handle handle; /* the handle of the hotk device */ + char status; /* status of the hotk, for LEDs, ... */ + u32 ledd_status; /* status of the LED display */ + u8 light_level; /* light sensor level */ + u8 light_switch; /* light sensor switch value */ + u16 event_count[128]; /* count for each event TODO make this better */ struct input_dev *inputdev; u16 *keycode_map; }; @@ -242,10 +254,12 @@ static struct backlight_ops asusbl_ops = { .update_status = update_bl_status, }; -/* These functions actually update the LED's, and are called from a +/* + * These functions actually update the LED's, and are called from a * workqueue. By doing this as separate work rather than when the LED * subsystem asks, we avoid messing with the Asus ACPI stuff during a - * potentially bad time, such as a timer interrupt. */ + * potentially bad time, such as a timer interrupt. + */ static struct workqueue_struct *led_workqueue; #define ASUS_LED(object, ledname, max) \ @@ -318,8 +332,8 @@ static struct key_entry asus_keymap[] = { static int write_acpi_int(acpi_handle handle, const char *method, int val, struct acpi_buffer *output) { - struct acpi_object_list params; //list of input parameters (an int here) - union acpi_object in_obj; //the only param we use + struct acpi_object_list params; /* list of input parameters (an int) */ + union acpi_object in_obj; /* the only param we use */ acpi_status status; if (!handle) @@ -574,7 +588,7 @@ static ssize_t show_infos(struct device *dev, { int len = 0; unsigned long long temp; - char buf[16]; //enough for all info + char buf[16]; /* enough for all info */ acpi_status rv = AE_OK; /* @@ -734,8 +748,10 @@ static int read_display(void) unsigned long long value = 0; acpi_status rv = AE_OK; - /* In most of the case, we know how to set the display, but sometime - we can't read it */ + /* + * In most of the case, we know how to set the display, but sometime + * we can't read it + */ if (display_get_handle) { rv = acpi_evaluate_integer(display_get_handle, NULL, NULL, &value); @@ -1152,8 +1168,10 @@ static int asus_hotk_get_info(void) ASUS_HANDLE_INIT(display_set); ASUS_HANDLE_INIT(display_get); - /* There is a lot of models with "ALSL", but a few get - a real light sens, so we need to check it. */ + /* + * There is a lot of models with "ALSL", but a few get + * a real light sens, so we need to check it. + */ if (!ASUS_HANDLE_INIT(ls_switch)) ASUS_HANDLE_INIT(ls_level); -- cgit v1.2.3-59-g8ed1b From a8258069793609903b5ebf0bca3320249154c379 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Sat, 29 Aug 2009 10:28:30 +0200 Subject: eeepc-laptop: fix rfkill memory leak on unload rfkill_unregister() should always be followed by rfkill_destroy() Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 819c685fe9cf..6f9a4489e199 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -985,6 +985,7 @@ static void eeepc_rfkill_exit(void) eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); if (ehotk->wlan_rfkill) { rfkill_unregister(ehotk->wlan_rfkill); + rfkill_destroy(ehotk->wlan_rfkill); ehotk->wlan_rfkill = NULL; } /* @@ -995,12 +996,21 @@ static void eeepc_rfkill_exit(void) if (ehotk->hotplug_slot) pci_hp_deregister(ehotk->hotplug_slot); - if (ehotk->bluetooth_rfkill) + if (ehotk->bluetooth_rfkill) { rfkill_unregister(ehotk->bluetooth_rfkill); - if (ehotk->wwan3g_rfkill) + rfkill_destroy(ehotk->bluetooth_rfkill); + ehotk->bluetooth_rfkill = NULL; + } + if (ehotk->wwan3g_rfkill) { rfkill_unregister(ehotk->wwan3g_rfkill); - if (ehotk->wimax_rfkill) + rfkill_destroy(ehotk->wwan3g_rfkill); + ehotk->wwan3g_rfkill = NULL; + } + if (ehotk->wimax_rfkill) { rfkill_unregister(ehotk->wimax_rfkill); + rfkill_destroy(ehotk->wimax_rfkill); + ehotk->wimax_rfkill = NULL; + } } static void eeepc_input_exit(void) -- cgit v1.2.3-59-g8ed1b From 52cc96bd5b61775db2792780c610979fc02313eb Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Sat, 29 Aug 2009 10:28:31 +0200 Subject: eeepc-laptop: allow rfkill hotplug to work on the 900A model The 900A provides hotplug notifications on a different ACPI object to other models. Reported-by: Trevor Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 6f9a4489e199..da3c08b3dcc1 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -981,6 +981,7 @@ static void eeepc_backlight_exit(void) static void eeepc_rfkill_exit(void) { + eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); if (ehotk->wlan_rfkill) { @@ -1101,6 +1102,7 @@ static int eeepc_rfkill_init(struct device *dev) if (result == -EBUSY) result = 0; + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); /* -- cgit v1.2.3-59-g8ed1b From 4e231fa4cbd3ff53fcb7d76eccd6fd86a152a95f Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Wed, 24 Jun 2009 15:17:36 +0800 Subject: ACPI video: ignore buggy _BQC _BQC doesn't return a value listed in _BCL method. http://bugzilla.kernel.org/show_bug.cgi?id=13511 ingore the buggy _BQC method in this case Signed-off-by: Vladimir Serbinenko Signed-off-by: Scott Howard Acked-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/video.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index a0cd0c7ee9e2..2020907921cc 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -603,6 +603,7 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, unsigned long long *level) { acpi_status status = AE_OK; + int i; if (device->cap._BQC || device->cap._BCQ) { char *buf = device->cap._BQC ? "_BQC" : "_BCQ"; @@ -618,8 +619,15 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, } *level += bqc_offset_aml_bug_workaround; - device->brightness->curr = *level; - return 0; + for (i = 2; i < device->brightness->count; i++) + if (device->brightness->levels[i] == *level) { + device->brightness->curr = *level; + return 0; + } + /* BQC returned an invalid level. Stop using it. */ + ACPI_WARNING((AE_INFO, "%s returned an invalid level", + buf)); + device->cap._BQC = device->cap._BCQ = 0; } else { /* Fixme: * should we return an error or ignore this failure? -- cgit v1.2.3-59-g8ed1b From bc76f90b8a5cf4aceedf210d08d5e8292f820cec Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 6 Aug 2009 15:57:48 -0700 Subject: ACPI battery: work around negative s16 battery current on Acer Acer Aspire 8930G laptops (and possibly others) report the battery current as a 16-bit signed negative when it is charging. It also reports it as 0x10000 when the current is 0. This patch adds a quirk for this which takes the absolute value of the reported current cast to an s16. This is a DSDT bug present in the latest BIOS revision (the EC register is 16 bits signed and the DSDT attempts to take the 16-bit two's complement of this, which works for discharge but not charge. It also breaks zero values because a 32-bit register is used and the high bits aren't thrown away). I've enabled this for all Acer systems which report in mA units. This should be safe since it won't break compliant systems unless they report a current above 32A, which is insane. The patch also detects the valid 32-bit value -1, which indicates unknown status, and does not attempt the fix in that case (note that this does not conflict with 16-bit -1, which is 65535 as read normally and gets translated to 1mA). Signed-off-by: Hector Martin Acked-by: Alexey Starikovskiy Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/battery.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 58b4517ce712..d7a786d5c4a5 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI_PROCFS_POWER #include @@ -85,6 +86,10 @@ static const struct acpi_device_id battery_device_ids[] = { MODULE_DEVICE_TABLE(acpi, battery_device_ids); +/* For buggy DSDTs that report negative 16-bit values for either charging + * or discharging current and/or report 0 as 65536 due to bad math. + */ +#define QUIRK_SIGNED16_CURRENT 0x0001 struct acpi_battery { struct mutex lock; @@ -112,6 +117,7 @@ struct acpi_battery { int state; int power_unit; u8 alarm_present; + long quirks; }; #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); @@ -390,6 +396,11 @@ static int acpi_battery_get_state(struct acpi_battery *battery) state_offsets, ARRAY_SIZE(state_offsets)); battery->update_time = jiffies; kfree(buffer.pointer); + + if ((battery->quirks & QUIRK_SIGNED16_CURRENT) && + battery->rate_now != -1) + battery->rate_now = abs((s16)battery->rate_now); + return result; } @@ -495,6 +506,14 @@ static void sysfs_remove_battery(struct acpi_battery *battery) } #endif +static void acpi_battery_quirks(struct acpi_battery *battery) +{ + battery->quirks = 0; + if (dmi_name_in_vendors("Acer") && battery->power_unit) { + battery->quirks |= QUIRK_SIGNED16_CURRENT; + } +} + static int acpi_battery_update(struct acpi_battery *battery) { int result, old_present = acpi_battery_present(battery); @@ -513,6 +532,7 @@ static int acpi_battery_update(struct acpi_battery *battery) result = acpi_battery_get_info(battery); if (result) return result; + acpi_battery_quirks(battery); acpi_battery_init_alarm(battery); } #ifdef CONFIG_ACPI_SYSFS_POWER -- cgit v1.2.3-59-g8ed1b From 2a84cb9852f52c0cd1c48bca41a8792d44ad06cc Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Sun, 30 Aug 2009 03:06:14 +0400 Subject: ACPI: EC: Merge IRQ and POLL modes In general, EC transaction should complete in less than 1ms, thus it is possible to merge wait for 1ms in poll mode and 1ms of interrupt transaction timeout. Still, driver will wait 500ms for EC to complete transaction. This significantly simplifies driver and makes it immune to problematic EC interrupt implementations. It also may lessen kernel start-up time by 500ms. References: http://bugzilla.kernel.org/show_bug.cgi?id=12949 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 140 ++++++++++++++++++------------------------------------ 1 file changed, 46 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 391f331674c7..839b542d5087 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -68,15 +68,13 @@ enum ec_command { #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_CDELAY 10 /* Wait 10us before polling EC */ +#define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ #define ACPI_EC_STORM_THRESHOLD 8 /* number of false interrupts per one transaction */ enum { EC_FLAGS_QUERY_PENDING, /* Query is pending */ - EC_FLAGS_GPE_MODE, /* Expect GPE to be sent - * for status change */ - EC_FLAGS_NO_GPE, /* Don't use GPE mode */ EC_FLAGS_GPE_STORM, /* GPE storm detected */ EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and * OpReg are installed */ @@ -170,7 +168,7 @@ static void start_transaction(struct acpi_ec *ec) acpi_ec_write_cmd(ec, ec->curr->command); } -static void gpe_transaction(struct acpi_ec *ec, u8 status) +static void advance_transaction(struct acpi_ec *ec, u8 status) { unsigned long flags; spin_lock_irqsave(&ec->curr_lock, flags); @@ -201,29 +199,6 @@ unlock: spin_unlock_irqrestore(&ec->curr_lock, flags); } -static int acpi_ec_wait(struct acpi_ec *ec) -{ - if (wait_event_timeout(ec->wait, ec_transaction_done(ec), - msecs_to_jiffies(ACPI_EC_DELAY))) - return 0; - /* try restart command if we get any false interrupts */ - if (ec->curr->irq_count && - (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { - pr_debug(PREFIX "controller reset, restart transaction\n"); - start_transaction(ec); - if (wait_event_timeout(ec->wait, ec_transaction_done(ec), - msecs_to_jiffies(ACPI_EC_DELAY))) - return 0; - } - /* missing GPEs, switch back to poll mode */ - if (printk_ratelimit()) - pr_info(PREFIX "missing confirmations, " - "switch off interrupt mode.\n"); - set_bit(EC_FLAGS_NO_GPE, &ec->flags); - clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); - return 1; -} - static void acpi_ec_gpe_query(void *ec_cxt); static int ec_check_sci(struct acpi_ec *ec, u8 state) @@ -236,43 +211,51 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state) return 0; } -static void ec_delay(void) -{ - /* EC in MSI notebooks don't tolerate delays other than 550 usec */ - if (EC_FLAGS_MSI) - udelay(ACPI_EC_DELAY); - else - /* Use shortest sleep available */ - msleep(1); -} - static int ec_poll(struct acpi_ec *ec) { - unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); - udelay(ACPI_EC_CDELAY); - while (time_before(jiffies, delay)) { - gpe_transaction(ec, acpi_ec_read_status(ec)); - ec_delay(); - if (ec_transaction_done(ec)) - return 0; + unsigned long flags; + int repeat = 2; /* number of command restarts */ + while (repeat--) { + unsigned long delay = jiffies + + msecs_to_jiffies(ACPI_EC_DELAY); + do { + /* don't sleep with disabled interrupts */ + if (EC_FLAGS_MSI || irqs_disabled()) { + udelay(ACPI_EC_MSI_UDELAY); + if (ec_transaction_done(ec)) + return 0; + } else { + if (wait_event_timeout(ec->wait, + ec_transaction_done(ec), + msecs_to_jiffies(1))) + return 0; + } + advance_transaction(ec, acpi_ec_read_status(ec)); + } while (time_before(jiffies, delay)); + if (!ec->curr->irq_count || + (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) + break; + /* try restart command if we get any false interrupts */ + pr_debug(PREFIX "controller reset, restart transaction\n"); + spin_lock_irqsave(&ec->curr_lock, flags); + start_transaction(ec); + spin_unlock_irqrestore(&ec->curr_lock, flags); } return -ETIME; } static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, - struct transaction *t, - int force_poll) + struct transaction *t) { unsigned long tmp; int ret = 0; pr_debug(PREFIX "transaction start\n"); /* disable GPE during transaction if storm is detected */ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { - clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); acpi_disable_gpe(NULL, ec->gpe); } if (EC_FLAGS_MSI) - udelay(ACPI_EC_DELAY); + udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ spin_lock_irqsave(&ec->curr_lock, tmp); /* following two actions should be kept atomic */ @@ -281,11 +264,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, if (ec->curr->command == ACPI_EC_COMMAND_QUERY) clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); spin_unlock_irqrestore(&ec->curr_lock, tmp); - /* if we selected poll mode or failed in GPE-mode do a poll loop */ - if (force_poll || - !test_bit(EC_FLAGS_GPE_MODE, &ec->flags) || - acpi_ec_wait(ec)) - ret = ec_poll(ec); + ret = ec_poll(ec); pr_debug(PREFIX "transaction end\n"); spin_lock_irqsave(&ec->curr_lock, tmp); ec->curr = NULL; @@ -295,8 +274,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, ec_check_sci(ec, acpi_ec_read_status(ec)); /* it is safe to enable GPE outside of transaction */ acpi_enable_gpe(NULL, ec->gpe); - } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && - t->irq_count > ACPI_EC_STORM_THRESHOLD) { + } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { pr_info(PREFIX "GPE storm detected, " "transactions will use polling mode\n"); set_bit(EC_FLAGS_GPE_STORM, &ec->flags); @@ -314,16 +292,14 @@ static int ec_wait_ibf0(struct acpi_ec *ec) { unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); /* interrupt wait manually if GPE mode is not active */ - unsigned long timeout = test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ? - msecs_to_jiffies(ACPI_EC_DELAY) : msecs_to_jiffies(1); while (time_before(jiffies, delay)) - if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), timeout)) + if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), + msecs_to_jiffies(1))) return 0; return -ETIME; } -static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t, - int force_poll) +static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) { int status; u32 glk; @@ -345,7 +321,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t, status = -ETIME; goto end; } - status = acpi_ec_transaction_unlocked(ec, t, force_poll); + status = acpi_ec_transaction_unlocked(ec, t); end: if (ec->global_lock) acpi_release_global_lock(glk); @@ -365,7 +341,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec) .wdata = NULL, .rdata = &d, .wlen = 0, .rlen = 1}; - return acpi_ec_transaction(ec, &t, 0); + return acpi_ec_transaction(ec, &t); } static int acpi_ec_burst_disable(struct acpi_ec *ec) @@ -375,7 +351,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec) .wlen = 0, .rlen = 0}; return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? - acpi_ec_transaction(ec, &t, 0) : 0; + acpi_ec_transaction(ec, &t) : 0; } static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) @@ -386,7 +362,7 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) .wdata = &address, .rdata = &d, .wlen = 1, .rlen = 1}; - result = acpi_ec_transaction(ec, &t, 0); + result = acpi_ec_transaction(ec, &t); *data = d; return result; } @@ -398,7 +374,7 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) .wdata = wdata, .rdata = NULL, .wlen = 2, .rlen = 0}; - return acpi_ec_transaction(ec, &t, 0); + return acpi_ec_transaction(ec, &t); } /* @@ -466,7 +442,7 @@ int ec_transaction(u8 command, if (!first_ec) return -ENODEV; - return acpi_ec_transaction(first_ec, &t, force_poll); + return acpi_ec_transaction(first_ec, &t); } EXPORT_SYMBOL(ec_transaction); @@ -487,7 +463,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) * bit to be cleared (and thus clearing the interrupt source). */ - result = acpi_ec_transaction(ec, &t, 0); + result = acpi_ec_transaction(ec, &t); if (result) return result; @@ -570,28 +546,10 @@ static u32 acpi_ec_gpe_handler(void *data) pr_debug(PREFIX "~~~> interrupt\n"); status = acpi_ec_read_status(ec); - if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) { - gpe_transaction(ec, status); - if (ec_transaction_done(ec) && - (status & ACPI_EC_FLAG_IBF) == 0) - wake_up(&ec->wait); - } - + advance_transaction(ec, status); + if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) + wake_up(&ec->wait); ec_check_sci(ec, status); - if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && - !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) { - /* this is non-query, must be confirmation */ - if (!test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { - if (printk_ratelimit()) - pr_info(PREFIX "non-query interrupt received," - " switching to interrupt mode\n"); - } else { - /* hush, STORM switches the mode every transaction */ - pr_debug(PREFIX "non-query interrupt received," - " switching to interrupt mode\n"); - } - set_bit(EC_FLAGS_GPE_MODE, &ec->flags); - } return ACPI_INTERRUPT_HANDLED; } @@ -837,8 +795,6 @@ static int acpi_ec_add(struct acpi_device *device) acpi_ec_add_fs(device); pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", ec->gpe, ec->command_addr, ec->data_addr); - pr_info(PREFIX "driver started in %s mode\n", - (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll"); return 0; } @@ -1054,8 +1010,6 @@ static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state) { struct acpi_ec *ec = acpi_driver_data(device); /* Stop using GPE */ - set_bit(EC_FLAGS_NO_GPE, &ec->flags); - clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); acpi_disable_gpe(NULL, ec->gpe); return 0; } @@ -1064,8 +1018,6 @@ static int acpi_ec_resume(struct acpi_device *device) { struct acpi_ec *ec = acpi_driver_data(device); /* Enable use of GPE back */ - clear_bit(EC_FLAGS_NO_GPE, &ec->flags); - set_bit(EC_FLAGS_GPE_MODE, &ec->flags); acpi_enable_gpe(NULL, ec->gpe); return 0; } -- cgit v1.2.3-59-g8ed1b From 6a63b06f3c494cc87eade97f081300bda60acec7 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 28 Aug 2009 23:29:44 +0400 Subject: ACPI: EC: use BURST mode only for MSI notebooks Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 839b542d5087..788db781a519 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -575,7 +575,8 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, if (bits != 8 && acpi_strict) return AE_BAD_PARAMETER; - acpi_ec_burst_enable(ec); + if (EC_FLAGS_MSI) + acpi_ec_burst_enable(ec); if (function == ACPI_READ) { result = acpi_ec_read(ec, address, &temp); @@ -596,7 +597,8 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, } } - acpi_ec_burst_disable(ec); + if (EC_FLAGS_MSI) + acpi_ec_burst_disable(ec); switch (result) { case -EINVAL: -- cgit v1.2.3-59-g8ed1b From f25752e67d9d9ee7562ae9944314dd8c057d3fa2 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 28 Aug 2009 23:29:51 +0400 Subject: ACPI: EC: Drop orphan comment Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 788db781a519..dc5561809529 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -330,10 +330,6 @@ unlock: return status; } -/* - * Note: samsung nv5000 doesn't work with ec burst mode. - * http://bugzilla.kernel.org/show_bug.cgi?id=4980 - */ static int acpi_ec_burst_enable(struct acpi_ec *ec) { u8 d; -- cgit v1.2.3-59-g8ed1b From eb0ca849863ecdc593ba7faa95fda5695af891c8 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sat, 29 Aug 2009 22:39:06 -0400 Subject: ACPI: sleep: another HP DMI entry for init_set_sci_en_on_resume DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv3 Notebook PC") http://bugzilla.kernel.org/show_bug.cgi?id=13745 Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 42159a28f433..e0a74097a978 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -405,6 +405,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, }, { + .callback = init_set_sci_en_on_resume, + .ident = "Hewlett-Packard HP Pavilion dv3 Notebook PC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv3 Notebook PC"), + }, + }, + { .callback = init_old_suspend_ordering, .ident = "Panasonic CF51-2L", .matches = { -- cgit v1.2.3-59-g8ed1b From 4b4fe3b62e8d88068083218d3e42c45223b51d29 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 8 Aug 2009 00:26:25 -0700 Subject: ACPI: video - fix potential crash when unloading thermal_cooling_device_register() returns error encoded in a pointer when it fails in which case we need to explictly set device->cdev to NULL so we don't try to unregister it when unloading. Signed-off-by: Dmitry Torokhov Acked-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/video.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 2020907921cc..aab385188599 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -997,8 +997,18 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) device->cdev = thermal_cooling_device_register("LCD", device->dev, &video_cooling_ops); - if (IS_ERR(device->cdev)) + if (IS_ERR(device->cdev)) { + /* + * Set cdev to NULL so we don't crash trying to + * free it. + * Also, why the hell we are returning early and + * not attempt to register video output if cooling + * device registration failed? + * -- dtor + */ + device->cdev = NULL; return; + } dev_info(&device->dev->dev, "registered as cooling_device%d\n", device->cdev->id); -- cgit v1.2.3-59-g8ed1b From 4a703a8fe562824f269943d995ddff35077253a9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 29 Aug 2009 23:03:16 -0400 Subject: ACPI: video - rename cdev to cooling_dev -- syntax only Cdev name is normally used for ether class devices or character devices so rename member to avoid confusion for casual reader of the code. Signed-off-by: Dmitry Torokhov Signed-off-by: Len Brown --- drivers/acpi/video.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index aab385188599..a8432c291f40 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -198,7 +198,7 @@ struct acpi_video_device { struct acpi_device *dev; struct acpi_video_device_brightness *brightness; struct backlight_device *backlight; - struct thermal_cooling_device *cdev; + struct thermal_cooling_device *cooling_dev; struct output_device *output_dev; }; @@ -387,20 +387,20 @@ static struct output_properties acpi_output_properties = { /* thermal cooling device callbacks */ -static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned +static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned long *state) { - struct acpi_device *device = cdev->devdata; + struct acpi_device *device = cooling_dev->devdata; struct acpi_video_device *video = acpi_driver_data(device); *state = video->brightness->count - 3; return 0; } -static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned +static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long *state) { - struct acpi_device *device = cdev->devdata; + struct acpi_device *device = cooling_dev->devdata; struct acpi_video_device *video = acpi_driver_data(device); unsigned long long level; int offset; @@ -417,9 +417,9 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned } static int -video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) +video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state) { - struct acpi_device *device = cdev->devdata; + struct acpi_device *device = cooling_dev->devdata; struct acpi_video_device *video = acpi_driver_data(device); int level; @@ -995,29 +995,29 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) if (result) printk(KERN_ERR PREFIX "Create sysfs link\n"); - device->cdev = thermal_cooling_device_register("LCD", + device->cooling_dev = thermal_cooling_device_register("LCD", device->dev, &video_cooling_ops); - if (IS_ERR(device->cdev)) { + if (IS_ERR(device->cooling_dev)) { /* - * Set cdev to NULL so we don't crash trying to + * Set cooling_dev to NULL so we don't crash trying to * free it. * Also, why the hell we are returning early and * not attempt to register video output if cooling * device registration failed? * -- dtor */ - device->cdev = NULL; + device->cooling_dev = NULL; return; } dev_info(&device->dev->dev, "registered as cooling_device%d\n", - device->cdev->id); + device->cooling_dev->id); result = sysfs_create_link(&device->dev->dev.kobj, - &device->cdev->device.kobj, + &device->cooling_dev->device.kobj, "thermal_cooling"); if (result) printk(KERN_ERR PREFIX "Create sysfs link\n"); - result = sysfs_create_link(&device->cdev->device.kobj, + result = sysfs_create_link(&device->cooling_dev->device.kobj, &device->dev->dev.kobj, "device"); if (result) printk(KERN_ERR PREFIX "Create sysfs link\n"); @@ -2020,13 +2020,13 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) acpi_video_device_notify); sysfs_remove_link(&device->backlight->dev.kobj, "device"); backlight_device_unregister(device->backlight); - if (device->cdev) { + if (device->cooling_dev) { sysfs_remove_link(&device->dev->dev.kobj, "thermal_cooling"); - sysfs_remove_link(&device->cdev->device.kobj, + sysfs_remove_link(&device->cooling_dev->device.kobj, "device"); - thermal_cooling_device_unregister(device->cdev); - device->cdev = NULL; + thermal_cooling_device_unregister(device->cooling_dev); + device->cooling_dev = NULL; } video_output_unregister(device->output_dev); -- cgit v1.2.3-59-g8ed1b From 90c53ca426cb93d15eefea79dcf6bd15ad3ffeb4 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 31 Aug 2009 12:39:54 -0400 Subject: ACPI video: work-around BIOS AML bug in _BQC _BQC on some laptops returns an uninitialized value when it's invoked for the first time. Set the laptop to the maximum backlight level in this case. http://bugzilla.kernel.org/attachment.cgi?id=22675 Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/video.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index a8432c291f40..097f24c87d82 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -878,7 +878,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) br->flags._BCM_use_index = br->flags._BCL_use_index; /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ - br->curr = level_old = max_level; + br->curr = level = max_level; if (!device->cap._BQC) goto set_level; @@ -900,15 +900,25 @@ acpi_video_init_brightness(struct acpi_video_device *device) br->flags._BQC_use_index = (level == max_level ? 0 : 1); - if (!br->flags._BQC_use_index) + if (!br->flags._BQC_use_index) { + /* + * Set the backlight to the initial state. + * On some buggy laptops, _BQC returns an uninitialized value + * when invoked for the first time, i.e. level_old is invalid. + * set the backlight to max_level in this case + */ + for (i = 2; i < br->count; i++) + if (level_old == br->levels[i]) + level = level_old; goto set_level; + } if (br->flags._BCL_reversed) level_old = (br->count - 1) - level_old; - level_old = br->levels[level_old]; + level = br->levels[level_old]; set_level: - result = acpi_video_device_lcd_set_level(device, level_old); + result = acpi_video_device_lcd_set_level(device, level); if (result) goto out_free_levels; -- cgit v1.2.3-59-g8ed1b From 7e24bc1ce669b2876ffa475ea1147f2bb9ffdc52 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 4 Aug 2009 14:44:17 -0600 Subject: ACPI: pci_slot.ko wants a 64-bit _SUN Similar to commit b6adc195 (PCI hotplug: acpiphp wants a 64-bit _SUN), pci_slot.ko reads and creates sysfs directories based on the _SUN method. Certain HP platforms return 64 bits in _SUN. This change to pci_slot.ko allows us to see the correct sysfs directories. Reported-by: Chad Smith Cc: stable@kernel.org Signed-off-by: Alex Chiang Signed-off-by: Len Brown --- drivers/acpi/pci_slot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 12158e0d009b..da9d6d25cf6d 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -57,7 +57,7 @@ ACPI_MODULE_NAME("pci_slot"); MY_NAME , ## arg); \ } while (0) -#define SLOT_NAME_SIZE 20 /* Inspired by #define in acpiphp.h */ +#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */ struct acpi_pci_slot { acpi_handle root_handle; /* handle of the root bridge */ @@ -149,7 +149,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } - snprintf(name, sizeof(name), "%u", (u32)sun); + snprintf(name, sizeof(name), "%llu", sun); pci_slot = pci_create_slot(pci_bus, device, name, NULL); if (IS_ERR(pci_slot)) { err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot)); -- cgit v1.2.3-59-g8ed1b From 718fb0de8ff88f71b3b91a8ee8e42e60c88e5128 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Thu, 6 Aug 2009 23:18:12 +0000 Subject: ACPI: fix NULL bug for HID/UID string acpi_device->pnp.hardware_id and unique_id are now allocated pointers, replacing the previous arrays. acpi_device_install_notify_handler() oopsed on the NULL hid when probing the video device, and perhaps other uses are vulnerable too. So initialize those pointers to empty strings when there is no hid or uid. Also, free hardware_id and unique_id when when acpi_device is going to be freed. http://bugzilla.kernel.org/show_bug.cgi?id=14096 Signed-off-by: Hugh Dickins Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/scan.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 9606af13d3b8..dc14421b93f1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -309,6 +309,10 @@ static void acpi_device_release(struct device *dev) struct acpi_device *acpi_dev = to_acpi_device(dev); kfree(acpi_dev->pnp.cid_list); + if (acpi_dev->flags.hardware_id) + kfree(acpi_dev->pnp.hardware_id); + if (acpi_dev->flags.unique_id) + kfree(acpi_dev->pnp.unique_id); kfree(acpi_dev); } @@ -1137,8 +1141,9 @@ static void acpi_device_set_id(struct acpi_device *device, strcpy(device->pnp.hardware_id, hid); device->flags.hardware_id = 1; } - } else - device->pnp.hardware_id = NULL; + } + if (!device->flags.hardware_id) + device->pnp.hardware_id = ""; if (uid) { device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); @@ -1146,8 +1151,9 @@ static void acpi_device_set_id(struct acpi_device *device, strcpy(device->pnp.unique_id, uid); device->flags.unique_id = 1; } - } else - device->pnp.unique_id = NULL; + } + if (!device->flags.unique_id) + device->pnp.unique_id = ""; if (cid_list || cid_add) { struct acpica_device_id_list *list; @@ -1362,10 +1368,8 @@ acpi_add_single_object(struct acpi_device **child, end: if (!result) *child = device; - else { - kfree(device->pnp.cid_list); - kfree(device); - } + else + acpi_device_release(&device->dev); return result; } -- cgit v1.2.3-59-g8ed1b From f61f925859c57f6175082aeeee17743c68558a6e Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sat, 5 Sep 2009 13:33:23 -0400 Subject: Revert "ACPI: Attach the ACPI device to the ACPI handle as early as possible" This reverts commit eab4b645769fa2f8703f5a3cb0cc4ac090d347af. http://bugzilla.kernel.org/show_bug.cgi?id=13002 Signed-off-by: Len Brown --- drivers/acpi/scan.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 781435d7e369..5dd702c9c1fa 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1263,16 +1263,6 @@ acpi_add_single_object(struct acpi_device **child, */ acpi_device_set_id(device, parent, handle, type); - /* - * The ACPI device is attached to acpi handle before getting - * the power/wakeup/peformance flags. Otherwise OS can't get - * the corresponding ACPI device by the acpi handle in the course - * of getting the power/wakeup/performance flags. - */ - result = acpi_device_set_context(device, type); - if (result) - goto end; - /* * Power Management * ---------------- @@ -1303,6 +1293,8 @@ acpi_add_single_object(struct acpi_device **child, goto end; } + if ((result = acpi_device_set_context(device, type))) + goto end; result = acpi_device_register(device, parent); -- cgit v1.2.3-59-g8ed1b From 307a042416dfc2216251a85b79e8578b65fdc0e7 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Sep 2009 09:55:40 +0800 Subject: ACPICA: Fix extraneous warning if _DSM returns a package _DSM can return any type of object, so validation on the return type cannot be performed. ACPICA BZ 802. http://www.acpica.org/bugzilla/show_bug.cgi?id=802 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/nspredef.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 8314e6a9e726..f8427afeebdf 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -193,11 +193,15 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, } /* - * We have a return value, but if one wasn't expected, just exit, this is + * 1) We have a return value, but if one wasn't expected, just exit, this is * not a problem. For example, if the "Implicit Return" feature is * enabled, methods will always return a value. + * + * 2) If the return value can be of any type, then we cannot perform any + * validation, exit. */ - if (!predefined->info.expected_btypes) { + if ((!predefined->info.expected_btypes) || + (predefined->info.expected_btypes == ACPI_RTYPE_ALL)) { goto cleanup; } -- cgit v1.2.3-59-g8ed1b From e678902ee899f6b0ab48166b410cdc9f1c27a350 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Sep 2009 09:58:14 +0800 Subject: ACPICA: Remove error message for Store(Localx,Localx) We silently ignore this construct for Windows compatibility ACPICA BZ 785. http://www.acpica.org/bugzilla/show_bug.cgi?id=785 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/dsmthdat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 22b1a3ce2c94..7d077bb2f525 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -433,10 +433,10 @@ acpi_ds_method_data_get_value(u8 type, case ACPI_REFCLASS_LOCAL: - ACPI_ERROR((AE_INFO, - "Uninitialized Local[%d] at node %p", - index, node)); - + /* + * No error message for this case, will be trapped again later to + * detect and ignore cases of Store(local_x,local_x) + */ return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL); default: -- cgit v1.2.3-59-g8ed1b From e3fe0913b8e732ae636cf23afca76cf2c30718e5 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Sep 2009 10:03:37 +0800 Subject: ACPICA: Fix memory leak for ill-formed Package objects Fixes a possible memory leak in the interpreter for package objects if the package initializer list is longer than the defined size of the package. This apparently can only happen if the BIOS changes the package size on the fly (seen in a _PSS object), as both iASL and the other compiler do not allow this. The interpreter will truncate the package to the defined size (and issue an error message), but can leave the extra objects undeleted if they have been pre-created during the argument processing (such is the case if the package consists of a number of sub-packages as in the _PSS.) ACPICA BZ 805. http://www.acpica.org/bugzilla/show_bug.cgi?id=805 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/dsobject.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 02e6caad4a76..507e1f0bbdfd 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -482,14 +482,27 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, if (arg) { /* * num_elements was exhausted, but there are remaining elements in the - * package_list. + * package_list. Truncate the package to num_elements. * * Note: technically, this is an error, from ACPI spec: "It is an error * for NumElements to be less than the number of elements in the - * PackageList". However, for now, we just print an error message and - * no exception is returned. + * PackageList". However, we just print an error message and + * no exception is returned. This provides Windows compatibility. Some + * BIOSs will alter the num_elements on the fly, creating this type + * of ill-formed package object. */ while (arg) { + /* + * We must delete any package elements that were created earlier + * and are not going to be used because of the package truncation. + */ + if (arg->common.node) { + acpi_ut_remove_reference(ACPI_CAST_PTR + (union + acpi_operand_object, + arg->common.node)); + arg->common.node = NULL; + } /* Find out how many elements there really are */ @@ -498,7 +511,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, } ACPI_WARNING((AE_INFO, - "Package List length (%X) larger than NumElements count (%X), truncated\n", + "Package List length (0x%X) larger than NumElements count (0x%X), truncated\n", i, element_count)); } else if (i < element_count) { /* @@ -506,7 +519,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, * Note: this is not an error, the package is padded out with NULLs. */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Package List length (%X) smaller than NumElements count (%X), padded with null elements\n", + "Package List length (0x%X) smaller than NumElements count (0x%X), padded with null elements\n", i, element_count)); } -- cgit v1.2.3-59-g8ed1b From eb752552464dbb7a99f8a975ec3b9355893cedd4 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Sep 2009 10:05:08 +0800 Subject: ACPICA: Update _OSI with new Windows OS strings Added strings for Windows server 2008, Windows Vista SP1, Windows 7, and Windows server 2008 R2. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/aclocal.h | 3 +++ drivers/acpi/acpica/uteval.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index ff6689eba917..81e64f478679 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -898,6 +898,9 @@ struct acpi_bit_register_info { #define ACPI_OSI_WIN_XP_SP2 0x05 #define ACPI_OSI_WINSRV_2003_SP1 0x06 #define ACPI_OSI_WIN_VISTA 0x07 +#define ACPI_OSI_WINSRV_2008 0x08 +#define ACPI_OSI_WIN_VISTA_SP1 0x09 +#define ACPI_OSI_WIN_7 0x0A #define ACPI_ALWAYS_ILLEGAL 0x00 diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 5503307b8bb7..5d54e36ab453 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -69,6 +69,9 @@ static struct acpi_interface_info acpi_interfaces_supported[] = { {"Windows 2001 SP2", ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */ {"Windows 2001.1 SP1", ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */ {"Windows 2006", ACPI_OSI_WIN_VISTA}, /* Windows Vista - Added 03/2006 */ + {"Windows 2006.1", ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */ + {"Windows 2006 SP1", ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */ + {"Windows 2009", ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */ /* Feature Group Strings */ -- cgit v1.2.3-59-g8ed1b From 9e64155eb1b6ab78980db58cfd21385fa5f6b024 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Sep 2009 10:21:03 +0800 Subject: ACPICA: Windows compatibility: autoexecute root _INI method Add support for execution of an _INI method at the namespace root. Although not defined in the ACPI specification, this support was added to Windows around the Vista timeframe. It is added here for Windows compatibility. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/nsinit.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 2adfcf329e15..1d5b360eb25b 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -170,6 +170,21 @@ acpi_status acpi_ns_initialize_devices(void) goto error_exit; } + /* + * Execute the "global" _INI method that may appear at the root. This + * support is provided for Windows compatibility (Vista+) and is not + * part of the ACPI specification. + */ + info.evaluate_info->prefix_node = acpi_gbl_root_node; + info.evaluate_info->pathname = METHOD_NAME__INI; + info.evaluate_info->parameters = NULL; + info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE; + + status = acpi_ns_evaluate(info.evaluate_info); + if (ACPI_SUCCESS(status)) { + info.num_INI++; + } + /* Walk namespace to execute all _INIs on present devices */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, -- cgit v1.2.3-59-g8ed1b From 6da25bf51689a5cc60370d30275dbb9e6852e0cb Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:11 -0300 Subject: thinkpad-acpi: don't ask about brightness_mode for fw. 1V and 1R X40 (firmware 1V) and T41 (firmware 1R) have been confirmed to work well with the new defaults, so we can stop pestering people to confirm that fact. For now, whitelist just these two firmware types. It is best to have at least one more firmware type confirmed for Radeon 9xxx and Intel GMA-2 ThinkPads before removing the confirmation requests entirely. Reported-by: Robert de Rooy Signed-off-by: Henrique de Moraes Holschuh Cc: stable@kernel.org Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e85600852502..d287283b8aa5 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5655,16 +5655,16 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { /* Models with ATI GPUs known to require ECNVRAM mode */ TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */ - /* Models with ATI GPUs (waiting confirmation) */ - TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), + /* Models with ATI GPUs that can use ECNVRAM */ + TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), - /* Models with Intel Extreme Graphics 2 (waiting confirmation) */ + /* Models with Intel Extreme Graphics 2 */ + TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), - TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), /* Models with Intel GMA900 */ TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ -- cgit v1.2.3-59-g8ed1b From 600a99fa3b4ce4a54375fb089e5ce0f3a1c9a7e1 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:12 -0300 Subject: thinkpad-acpi: firmware version checks Use the quirk infrastructure to warn of outdated firmware and also of firmware versions that are known to cause problems. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 182 +++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d287283b8aa5..cc4155c3620e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1601,6 +1601,187 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) #endif } +/************************************************************************* + * Firmware Data + */ + +/* + * Table of recommended minimum BIOS versions + * + * Reasons for listing: + * 1. Stable BIOS, listed because the unknown ammount of + * bugs and bad ACPI behaviour on older versions + * + * 2. BIOS or EC fw with known bugs that trigger on Linux + * + * 3. BIOS with known reduced functionality in older versions + * + * We recommend the latest BIOS and EC version. + * We only support the latest BIOS and EC fw version as a rule. + * + * Sources: IBM ThinkPad Public Web Documents (update changelogs), + * Information from users in ThinkWiki + */ + +#define TPV_Q(__v, __id1, __id2, __bv1, __bv2) \ + { .vendor = (__v), \ + .bios = TPID(__id1, __id2), \ + .ec = TPACPI_MATCH_ANY, \ + .quirks = TPACPI_MATCH_ANY << 16 \ + | (__bv1) << 8 | (__bv2) } + +#define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \ + __eid1, __eid2, __ev1, __ev2) \ + { .vendor = (__v), \ + .bios = TPID(__bid1, __bid2), \ + .ec = TPID(__eid1, __eid2), \ + .quirks = (__ev1) << 24 | (__ev2) << 16 \ + | (__bv1) << 8 | (__bv2) } + +#define TPV_QI0(__id1, __id2, __bv1, __bv2) \ + TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2) + +#define TPV_QI1(__id1, __id2, __bv1, __bv2, __ev1, __ev2) \ + TPV_Q_X(PCI_VENDOR_ID_IBM, __id1, __id2, \ + __bv1, __bv2, __id1, __id2, __ev1, __ev2) + +#define TPV_QI2(__bid1, __bid2, __bv1, __bv2, \ + __eid1, __eid2, __ev1, __ev2) \ + TPV_Q_X(PCI_VENDOR_ID_IBM, __bid1, __bid2, \ + __bv1, __bv2, __eid1, __eid2, __ev1, __ev2) + +#define TPV_QL0(__id1, __id2, __bv1, __bv2) \ + TPV_Q(PCI_VENDOR_ID_LENOVO, __id1, __id2, __bv1, __bv2) + +#define TPV_QL1(__id1, __id2, __bv1, __bv2, __ev1, __ev2) \ + TPV_Q_X(PCI_VENDOR_ID_LENOVO, __id1, __id2, \ + __bv1, __bv2, __id1, __id2, __ev1, __ev2) + +#define TPV_QL2(__bid1, __bid2, __bv1, __bv2, \ + __eid1, __eid2, __ev1, __ev2) \ + TPV_Q_X(PCI_VENDOR_ID_LENOVO, __bid1, __bid2, \ + __bv1, __bv2, __eid1, __eid2, __ev1, __ev2) + +static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = { + /* Numeric models ------------------ */ + /* FW MODEL BIOS VERS */ + TPV_QI0('I', 'M', '6', '5'), /* 570 */ + TPV_QI0('I', 'U', '2', '6'), /* 570E */ + TPV_QI0('I', 'B', '5', '4'), /* 600 */ + TPV_QI0('I', 'H', '4', '7'), /* 600E */ + TPV_QI0('I', 'N', '3', '6'), /* 600E */ + TPV_QI0('I', 'T', '5', '5'), /* 600X */ + TPV_QI0('I', 'D', '4', '8'), /* 770, 770E, 770ED */ + TPV_QI0('I', 'I', '4', '2'), /* 770X */ + TPV_QI0('I', 'O', '2', '3'), /* 770Z */ + + /* A-series ------------------------- */ + /* FW MODEL BIOS VERS EC VERS */ + TPV_QI0('I', 'W', '5', '9'), /* A20m */ + TPV_QI0('I', 'V', '6', '9'), /* A20p */ + TPV_QI0('1', '0', '2', '6'), /* A21e, A22e */ + TPV_QI0('K', 'U', '3', '6'), /* A21e */ + TPV_QI0('K', 'X', '3', '6'), /* A21m, A22m */ + TPV_QI0('K', 'Y', '3', '8'), /* A21p, A22p */ + TPV_QI0('1', 'B', '1', '7'), /* A22e */ + TPV_QI0('1', '3', '2', '0'), /* A22m */ + TPV_QI0('1', 'E', '7', '3'), /* A30/p (0) */ + TPV_QI1('1', 'G', '4', '1', '1', '7'), /* A31/p (0) */ + TPV_QI1('1', 'N', '1', '6', '0', '7'), /* A31/p (0) */ + + /* G-series ------------------------- */ + /* FW MODEL BIOS VERS */ + TPV_QI0('1', 'T', 'A', '6'), /* G40 */ + TPV_QI0('1', 'X', '5', '7'), /* G41 */ + + /* R-series, T-series --------------- */ + /* FW MODEL BIOS VERS EC VERS */ + TPV_QI0('1', 'C', 'F', '0'), /* R30 */ + TPV_QI0('1', 'F', 'F', '1'), /* R31 */ + TPV_QI0('1', 'M', '9', '7'), /* R32 */ + TPV_QI0('1', 'O', '6', '1'), /* R40 */ + TPV_QI0('1', 'P', '6', '5'), /* R40 */ + TPV_QI0('1', 'S', '7', '0'), /* R40e */ + TPV_QI1('1', 'R', 'D', 'R', '7', '1'), /* R50/p, R51, + T40/p, T41/p, T42/p (1) */ + TPV_QI1('1', 'V', '7', '1', '2', '8'), /* R50e, R51 (1) */ + TPV_QI1('7', '8', '7', '1', '0', '6'), /* R51e (1) */ + TPV_QI1('7', '6', '6', '9', '1', '6'), /* R52 (1) */ + TPV_QI1('7', '0', '6', '9', '2', '8'), /* R52, T43 (1) */ + + TPV_QI0('I', 'Y', '6', '1'), /* T20 */ + TPV_QI0('K', 'Z', '3', '4'), /* T21 */ + TPV_QI0('1', '6', '3', '2'), /* T22 */ + TPV_QI1('1', 'A', '6', '4', '2', '3'), /* T23 (0) */ + TPV_QI1('1', 'I', '7', '1', '2', '0'), /* T30 (0) */ + TPV_QI1('1', 'Y', '6', '5', '2', '9'), /* T43/p (1) */ + + TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */ + TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */ + TPV_QL0('7', 'E', 'D', '0'), /* R60e, R60i */ + + /* BIOS FW BIOS VERS EC FW EC VERS */ + TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */ + TPV_QL2('7', 'I', '3', '4', '7', '9', '5', '0'), /* T60/p wide */ + + /* X-series ------------------------- */ + /* FW MODEL BIOS VERS EC VERS */ + TPV_QI0('I', 'Z', '9', 'D'), /* X20, X21 */ + TPV_QI0('1', 'D', '7', '0'), /* X22, X23, X24 */ + TPV_QI1('1', 'K', '4', '8', '1', '8'), /* X30 (0) */ + TPV_QI1('1', 'Q', '9', '7', '2', '3'), /* X31, X32 (0) */ + TPV_QI1('1', 'U', 'D', '3', 'B', '2'), /* X40 (0) */ + TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */ + TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */ + + TPV_QL0('7', 'B', 'D', '7'), /* X60/s */ + TPV_QL0('7', 'J', '3', '0'), /* X60t */ + + /* (0) - older versions lack DMI EC fw string and functionality */ + /* (1) - older versions known to lack functionality */ +}; + +#undef TPV_QL1 +#undef TPV_QL0 +#undef TPV_QI2 +#undef TPV_QI1 +#undef TPV_QI0 +#undef TPV_Q_X +#undef TPV_Q + +static void __init tpacpi_check_outdated_fw(void) +{ + unsigned long fwvers; + u16 ec_version, bios_version; + + fwvers = tpacpi_check_quirks(tpacpi_bios_version_qtable, + ARRAY_SIZE(tpacpi_bios_version_qtable)); + + if (!fwvers) + return; + + bios_version = fwvers & 0xffffU; + ec_version = (fwvers >> 16) & 0xffffU; + + /* note that unknown versions are set to 0x0000 and we use that */ + if ((bios_version > thinkpad_id.bios_release) || + (ec_version > thinkpad_id.ec_release && + ec_version != TPACPI_MATCH_ANY)) { + /* + * The changelogs would let us track down the exact + * reason, but it is just too much of a pain to track + * it. We only list BIOSes that are either really + * broken, or really stable to begin with, so it is + * best if the user upgrades the firmware anyway. + */ + printk(TPACPI_WARN + "WARNING: Outdated ThinkPad BIOS/EC firmware\n"); + printk(TPACPI_WARN + "WARNING: This firmware may be missing critical bug " + "fixes and/or important features\n"); + } +} + /**************************************************************************** **************************************************************************** * @@ -1634,6 +1815,7 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) (thinkpad_id.nummodel_str) ? thinkpad_id.nummodel_str : "unknown"); + tpacpi_check_outdated_fw(); return 0; } -- cgit v1.2.3-59-g8ed1b From e675abafcc0df38125e6e94a9ba91c92fe774f52 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:13 -0300 Subject: thinkpad-acpi: be more strict when detecting a ThinkPad Use stricter checks to decide that we're running on a supported ThinkPad. This should remove some possible false positives, although nobody ever bothered to report any. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cc4155c3620e..d69ab3f0bdbc 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1621,6 +1621,9 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) * * Sources: IBM ThinkPad Public Web Documents (update changelogs), * Information from users in ThinkWiki + * + * WARNING: we use this table also to detect that the machine is + * a ThinkPad in some cases, so don't remove entries lightly. */ #define TPV_Q(__v, __id1, __id2, __bv1, __bv2) \ @@ -1782,6 +1785,12 @@ static void __init tpacpi_check_outdated_fw(void) } } +static bool __init tpacpi_is_fw_known(void) +{ + return tpacpi_check_quirks(tpacpi_bios_version_qtable, + ARRAY_SIZE(tpacpi_bios_version_qtable)) != 0; +} + /**************************************************************************** **************************************************************************** * @@ -7706,9 +7715,11 @@ static int __init probe_for_thinkpad(void) /* * Non-ancient models have better DMI tagging, but very old models - * don't. + * don't. tpacpi_is_fw_known() is a cheat to help in that case. */ - is_thinkpad = (thinkpad_id.model_str != NULL); + is_thinkpad = (thinkpad_id.model_str != NULL) || + (thinkpad_id.ec_model != 0) || + tpacpi_is_fw_known(); /* ec is required because many other handles are relative to it */ TPACPI_ACPIHANDLE_INIT(ec); @@ -7719,13 +7730,6 @@ static int __init probe_for_thinkpad(void) return -ENODEV; } - /* - * Risks a regression on very old machines, but reduces potential - * false positives a damn great deal - */ - if (!is_thinkpad) - is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM); - if (!is_thinkpad && !force_load) return -ENODEV; -- cgit v1.2.3-59-g8ed1b From db25f16d1dcce8de12f2f5daf884cda02196b28c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:14 -0300 Subject: thinkpad-acpi: hotkey poll fixes Fix some locking, avoid exiting the kthread before kthread_stop() is called on it, and clean up the hotkey poll routines a little bit. Also, restore bits in the firmware mask after hotkey_source_mask is changed. Without this, we leave events disabled... Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 108 +++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d69ab3f0bdbc..679a73b43191 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1922,16 +1922,42 @@ struct tp_nvram_state { u8 volume_level; }; +/* kthread for the hotkey poller */ static struct task_struct *tpacpi_hotkey_task; -static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ -static int hotkey_poll_freq = 10; /* Hz */ + +/* Acquired while the poller kthread is running, use to sync start/stop */ static struct mutex hotkey_thread_mutex; + +/* + * Acquire mutex to write poller control variables. + * Increment hotkey_config_change when changing them. + * + * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END + */ static struct mutex hotkey_thread_data_mutex; static unsigned int hotkey_config_change; +/* + * hotkey poller control variables + * + * Must be atomic or readers will also need to acquire mutex + */ +static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ +static unsigned int hotkey_poll_freq = 10; /* Hz */ + +#define HOTKEY_CONFIG_CRITICAL_START \ + do { \ + mutex_lock(&hotkey_thread_data_mutex); \ + hotkey_config_change++; \ + } while (0); +#define HOTKEY_CONFIG_CRITICAL_END \ + mutex_unlock(&hotkey_thread_data_mutex); + #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ #define hotkey_source_mask 0U +#define HOTKEY_CONFIG_CRITICAL_START +#define HOTKEY_CONFIG_CRITICAL_END #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ @@ -1956,19 +1982,6 @@ static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL -#define HOTKEY_CONFIG_CRITICAL_START \ - do { \ - mutex_lock(&hotkey_thread_data_mutex); \ - hotkey_config_change++; \ - } while (0); -#define HOTKEY_CONFIG_CRITICAL_END \ - mutex_unlock(&hotkey_thread_data_mutex); -#else -#define HOTKEY_CONFIG_CRITICAL_START -#define HOTKEY_CONFIG_CRITICAL_END -#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ - /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) @@ -2013,7 +2026,9 @@ static int hotkey_mask_get(void) if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) return -EIO; } + HOTKEY_CONFIG_CRITICAL_START hotkey_mask = m | (hotkey_source_mask & hotkey_mask); + HOTKEY_CONFIG_CRITICAL_END return 0; } @@ -2266,6 +2281,7 @@ static int hotkey_kthread(void *data) unsigned int si, so; unsigned long t; unsigned int change_detector, must_reset; + unsigned int poll_freq; mutex_lock(&hotkey_thread_mutex); @@ -2282,12 +2298,17 @@ static int hotkey_kthread(void *data) mutex_lock(&hotkey_thread_data_mutex); change_detector = hotkey_config_change; mask = hotkey_source_mask & hotkey_mask; + poll_freq = hotkey_poll_freq; mutex_unlock(&hotkey_thread_data_mutex); hotkey_read_nvram(&s[so], mask); - while (!kthread_should_stop() && hotkey_poll_freq) { - if (t == 0) - t = 1000/hotkey_poll_freq; + while (!kthread_should_stop()) { + if (t == 0) { + if (likely(poll_freq)) + t = 1000/poll_freq; + else + t = 100; /* should never happen... */ + } t = msleep_interruptible(t); if (unlikely(kthread_should_stop())) break; @@ -2303,6 +2324,7 @@ static int hotkey_kthread(void *data) change_detector = hotkey_config_change; } mask = hotkey_source_mask & hotkey_mask; + poll_freq = hotkey_poll_freq; mutex_unlock(&hotkey_thread_data_mutex); if (likely(mask)) { @@ -2322,6 +2344,7 @@ exit: return 0; } +/* call with hotkey_mutex held */ static void hotkey_poll_stop_sync(void) { if (tpacpi_hotkey_task) { @@ -2338,10 +2361,11 @@ static void hotkey_poll_stop_sync(void) } /* call with hotkey_mutex held */ -static void hotkey_poll_setup(int may_warn) +static void hotkey_poll_setup(bool may_warn) { - if ((hotkey_source_mask & hotkey_mask) != 0 && - hotkey_poll_freq > 0 && + u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask; + + if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 && (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { if (!tpacpi_hotkey_task) { tpacpi_hotkey_task = kthread_run(hotkey_kthread, @@ -2355,26 +2379,37 @@ static void hotkey_poll_setup(int may_warn) } } else { hotkey_poll_stop_sync(); - if (may_warn && - hotkey_source_mask != 0 && hotkey_poll_freq == 0) { + if (may_warn && hotkeys_to_poll != 0 && + hotkey_poll_freq == 0) { printk(TPACPI_NOTICE "hot keys 0x%08x require polling, " "which is currently disabled\n", - hotkey_source_mask); + hotkeys_to_poll); } } } -static void hotkey_poll_setup_safe(int may_warn) +static void hotkey_poll_setup_safe(bool may_warn) { mutex_lock(&hotkey_mutex); hotkey_poll_setup(may_warn); mutex_unlock(&hotkey_mutex); } +/* call with hotkey_mutex held */ +static void hotkey_poll_set_freq(unsigned int freq) +{ + if (!freq) + hotkey_poll_stop_sync(); + + HOTKEY_CONFIG_CRITICAL_START + hotkey_poll_freq = freq; + HOTKEY_CONFIG_CRITICAL_END +} + #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ -static void hotkey_poll_setup_safe(int __unused) +static void hotkey_poll_setup_safe(bool __unused) { } @@ -2392,7 +2427,7 @@ static int hotkey_inputdev_open(struct input_dev *dev) case TPACPI_LIFE_EXITING: return -EBUSY; case TPACPI_LIFE_RUNNING: - hotkey_poll_setup_safe(0); + hotkey_poll_setup_safe(false); return 0; } @@ -2405,7 +2440,7 @@ static void hotkey_inputdev_close(struct input_dev *dev) { /* disable hotkey polling when possible */ if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) - hotkey_poll_setup_safe(0); + hotkey_poll_setup_safe(false); } /* sysfs hotkey enable ------------------------------------------------- */ @@ -2479,7 +2514,7 @@ static ssize_t hotkey_mask_store(struct device *dev, res = hotkey_mask_set(t); #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - hotkey_poll_setup(1); + hotkey_poll_setup(true); #endif mutex_unlock(&hotkey_mutex); @@ -2568,7 +2603,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, hotkey_source_mask = t; HOTKEY_CONFIG_CRITICAL_END - hotkey_poll_setup(1); + hotkey_poll_setup(true); + hotkey_mask_set(hotkey_mask); mutex_unlock(&hotkey_mutex); @@ -2601,9 +2637,9 @@ static ssize_t hotkey_poll_freq_store(struct device *dev, if (mutex_lock_killable(&hotkey_mutex)) return -ERESTARTSYS; - hotkey_poll_freq = t; + hotkey_poll_set_freq(t); + hotkey_poll_setup(true); - hotkey_poll_setup(1); mutex_unlock(&hotkey_mutex); tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); @@ -2794,7 +2830,9 @@ static void tpacpi_send_radiosw_update(void) static void hotkey_exit(void) { #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + mutex_lock(&hotkey_mutex); hotkey_poll_stop_sync(); + mutex_unlock(&hotkey_mutex); #endif if (hotkey_dev_attributes) @@ -3031,7 +3069,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "hotkey source mask 0x%08x, polling freq %d\n", + "hotkey source mask 0x%08x, polling freq %u\n", hotkey_source_mask, hotkey_poll_freq); #endif @@ -3169,7 +3207,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) tpacpi_inputdev->open = &hotkey_inputdev_open; tpacpi_inputdev->close = &hotkey_inputdev_close; - hotkey_poll_setup_safe(1); + hotkey_poll_setup_safe(true); tpacpi_send_radiosw_update(); tpacpi_input_send_tabletsw(); @@ -3457,7 +3495,7 @@ static void hotkey_resume(void) hotkey_tablet_mode_notify_change(); hotkey_wakeup_reason_notify_change(); hotkey_wakeup_hotunplug_complete_notify_change(); - hotkey_poll_setup_safe(0); + hotkey_poll_setup_safe(false); } /* procfs -------------------------------------------------------------- */ -- cgit v1.2.3-59-g8ed1b From 06777be6d8688ba93103fffbbe9e64a5e6fab3c8 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:15 -0300 Subject: thinkpad-acpi: deprecate hotkey_bios_mask Some analysis of the ACPI DSDTs shows that the HKEY pre-enabled mask is always 0x80c (FN+F3,FN+F4 and FN+F12), which are the hotkeys that the second gen of HKEY firmware supported (the first gen didn't report any hotkeys, the second reported these tree hotkeys but had no mask support, and the third added mask support). So, this is probably some sort of backwards compatibility with older versions of the IBM ThinkVantage suite. We have no use for that, and I know of exactly ZERO users of that attribute, anyway. Start the process of getting rid of it. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 6 +++++- drivers/platform/x86/thinkpad_acpi.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index e2ddcdeb61b6..ab4b58eaa7f4 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -240,9 +240,13 @@ sysfs notes: Returns 0. hotkey_bios_mask: + DEPRECATED, DON'T USE, WILL BE REMOVED IN THE FUTURE. + Returns the hot keys mask when thinkpad-acpi was loaded. Upon module unload, the hot keys mask will be restored - to this value. + to this value. This is always 0x80c, because those are + the hotkeys that were supported by ancient firmware + without mask support. hotkey_enable: DEPRECATED, WILL BE REMOVED SOON. diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 679a73b43191..6b667891fc3b 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2544,6 +2544,8 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { + printk_deprecated_attribute("hotkey_bios_mask", + "This attribute is useless."); return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); } -- cgit v1.2.3-59-g8ed1b From 20c9aa46f644b3ddb161a819d1b0c2b07097c4ee Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:16 -0300 Subject: thinkpad-acpi: Fix procfs hotkey reset command echo "reset" > /proc/acpi/ibm/hotkey should do something non-useless, so instead of setting it to Fn+F2, Fn+F3, Fn+F5, set it to hotkey_recommended_mask. It is not like it will survive for much longer, anyway. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 2 +- drivers/platform/x86/thinkpad_acpi.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index ab4b58eaa7f4..6d03487ef1c7 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -219,7 +219,7 @@ The following commands can be written to the /proc/acpi/ibm/hotkey file: echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys ... any other 8-hex-digit mask ... - echo reset > /proc/acpi/ibm/hotkey -- restore the original mask + echo reset > /proc/acpi/ibm/hotkey -- restore the recommended mask The following commands have been deprecated and will cause the kernel to log a warning: diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 6b667891fc3b..dd779e54894f 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3569,7 +3569,8 @@ static int hotkey_write(char *buf) hotkey_enabledisable_warn(0); res = -EPERM; } else if (strlencmp(cmd, "reset") == 0) { - mask = hotkey_orig_mask; + mask = (hotkey_all_mask | hotkey_source_mask) + & ~hotkey_reserved_mask; } else if (sscanf(cmd, "0x%x", &mask) == 1) { /* mask set */ } else if (sscanf(cmd, "%x", &mask) == 1) { -- cgit v1.2.3-59-g8ed1b From 230d8cf25ac32c7d2fdb4dda861ec5d954000ffb Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:17 -0300 Subject: thinkpad-acpi: don't poll by default any of the reserved hotkeys Init hotkey_source_mask late, so that we can make use of hotkey_reserved_mask to avoid polling any of the reserved hotkeys by default. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index dd779e54894f..9c3bb0c498e1 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3062,19 +3062,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; } -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - if (tp_features.hotkey_mask) { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK - & ~hotkey_all_mask; - } else { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; - } - - vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "hotkey source mask 0x%08x, polling freq %u\n", - hotkey_source_mask, hotkey_poll_freq); -#endif - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wlswemul) { tp_features.hotkey_wlsw = 1; @@ -3186,6 +3173,21 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | (1 << TP_ACPI_HOTKEYSCAN_FNEND); } +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + if (tp_features.hotkey_mask) { + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK + & ~hotkey_all_mask + & ~hotkey_reserved_mask; + } else { + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK + & ~hotkey_reserved_mask; + } + + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "hotkey source mask 0x%08x, polling freq %u\n", + hotkey_source_mask, hotkey_poll_freq); +#endif + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "enabling firmware HKEY event interface...\n"); res = hotkey_status_set(true); -- cgit v1.2.3-59-g8ed1b From de4c8cc7bddd9c43dc1b85517ab445ffa8163058 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 12 Sep 2009 15:22:18 -0300 Subject: thinkpad-acpi: report brightness events when required Report KEY_BRIGHTNESSUP and KEY_BRIGHTNESSDOWN input events when the ThinkPad is in "passive brightness control" mode (because either we or ACPI video touched _BCL), and ACPI video is not processing these events by itself. This happens only on Lenovo ThinkPads with ACPI video support, when operating with the ACPI video driver in acpi_backlight=vendor mode. Issuing these events is the right thing to do, and will work around bugzilla #13368, if userspace is properly configured and actively handles these events. For other ThinkPads, and when ACPI video is handling brightness changes, thinkpad-acpi will continue NOT sending KEY_BRIGHTNESS* events by default. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9c3bb0c498e1..955adf67e8f0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2854,6 +2854,15 @@ static void hotkey_exit(void) } } +static void __init hotkey_unmap(const unsigned int scancode) +{ + if (hotkey_keycode_map[scancode] != KEY_RESERVED) { + clear_bit(hotkey_keycode_map[scancode], + tpacpi_inputdev->keybit); + hotkey_keycode_map[scancode] = KEY_RESERVED; + } +} + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -2932,11 +2941,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ - /* These either have to go through ACPI video, or - * act like in the IBM ThinkPads, so don't ever - * enable them by default */ - KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ - KEY_RESERVED, /* 0x10: FN+END (brightness down) */ + /* These should be enabled --only-- when ACPI video + * is disabled (i.e. in "vendor" mode), and are handled + * in a special way by the init code */ + KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ + KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ @@ -3162,15 +3171,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) "Disabling thinkpad-acpi brightness events " "by default...\n"); - /* The hotkey_reserved_mask change below is not - * necessary while the keys are at KEY_RESERVED in the - * default map, but better safe than sorry, leave it - * here as a marker of what we have to do, especially - * when we finally become able to set this at runtime - * on response to X.org requests */ + /* Disable brightness up/down on Lenovo thinkpads when + * ACPI is handling them, otherwise it is plain impossible + * for userspace to do something even remotely sane */ hotkey_reserved_mask |= (1 << TP_ACPI_HOTKEYSCAN_FNHOME) | (1 << TP_ACPI_HOTKEYSCAN_FNEND); + hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNHOME); + hotkey_unmap(TP_ACPI_HOTKEYSCAN_FNEND); } #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL -- cgit v1.2.3-59-g8ed1b From 5f0dadb4bd259c3b832e19702f552947244edfb9 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 14 Sep 2009 12:43:52 +0200 Subject: thinkpad_acpi: fix rfkill memory leak on unload rfkill_unregister() should always be followed by rfkill_destroy() Signed-off-by: Corentin Chary Acked-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 955adf67e8f0..f78d27503925 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1278,6 +1278,7 @@ static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id) tp_rfk = tpacpi_rfkill_switches[id]; if (tp_rfk) { rfkill_unregister(tp_rfk->rfkill); + rfkill_destroy(tp_rfk->rfkill); tpacpi_rfkill_switches[id] = NULL; kfree(tp_rfk); } -- cgit v1.2.3-59-g8ed1b From 9caeb5324427990db7bc97e674794d201c1f0797 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 14 Sep 2009 21:11:21 -0300 Subject: topstar-laptop: add new driver for hotkeys support on Topstar N01 This adds Topstar Laptop Extras ACPI driver. It enables hotkeys functionality with Topstar N01 netbook. Besides hotkeys there are other functions exposed by its ACPI firmware, but for now only hotkeys reporting on Topstar N01 is supported. Topstar is a chinese manufacturer, its website can be currently reached at http://www.topstardigital.cn/ Signed-off-by: Herton Ronaldo Krzesinski Reviewed-by: Alan Jenkins Reviewed-by: Bjorn Helgaas Signed-off-by: Len Brown --- MAINTAINERS | 5 + drivers/platform/x86/Kconfig | 9 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/topstar-laptop.c | 265 ++++++++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+) create mode 100644 drivers/platform/x86/topstar-laptop.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 8dca9d89c6c1..d75a7a70788e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4968,6 +4968,11 @@ T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches S: Maintained F: security/tomoyo/ +TOPSTAR LAPTOP EXTRAS DRIVER +M: Herton Ronaldo Krzesinski +S: Maintained +F: drivers/platform/x86/topstar-laptop.c + TOSHIBA ACPI EXTRAS DRIVER S: Orphan F: drivers/platform/x86/toshiba_acpi.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 77c6097ced80..48315621046d 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -396,6 +396,15 @@ config ACPI_ASUS NOTE: This driver is deprecated and will probably be removed soon, use asus-laptop instead. +config TOPSTAR_LAPTOP + tristate "Topstar Laptop Extras" + depends on ACPI + depends on INPUT + ---help--- + This driver adds support for hotkeys found on Topstar laptops. + + If you have a Topstar laptop, say Y or M here. + config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 641b8bfa5538..d1c16210a512 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -19,4 +19,5 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o +obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c new file mode 100644 index 000000000000..02f3d4e9e666 --- /dev/null +++ b/drivers/platform/x86/topstar-laptop.c @@ -0,0 +1,265 @@ +/* + * ACPI driver for Topstar notebooks (hotkeys support only) + * + * Copyright (c) 2009 Herton Ronaldo Krzesinski + * + * Implementation inspired by existing x86 platform drivers, in special + * asus/eepc/fujitsu-laptop, thanks to their authors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#define ACPI_TOPSTAR_CLASS "topstar" + +struct topstar_hkey { + struct input_dev *inputdev; +}; + +struct tps_key_entry { + u8 code; + u16 keycode; +}; + +static struct tps_key_entry topstar_keymap[] = { + { 0x80, KEY_BRIGHTNESSUP }, + { 0x81, KEY_BRIGHTNESSDOWN }, + { 0x83, KEY_VOLUMEUP }, + { 0x84, KEY_VOLUMEDOWN }, + { 0x85, KEY_MUTE }, + { 0x86, KEY_SWITCHVIDEOMODE }, + { 0x87, KEY_F13 }, /* touchpad enable/disable key */ + { 0x88, KEY_WLAN }, + { 0x8a, KEY_WWW }, + { 0x8b, KEY_MAIL }, + { 0x8c, KEY_MEDIA }, + { 0x96, KEY_F14 }, /* G key? */ + { } +}; + +static struct tps_key_entry *tps_get_key_by_scancode(int code) +{ + struct tps_key_entry *key; + + for (key = topstar_keymap; key->code; key++) + if (code == key->code) + return key; + + return NULL; +} + +static struct tps_key_entry *tps_get_key_by_keycode(int code) +{ + struct tps_key_entry *key; + + for (key = topstar_keymap; key->code; key++) + if (code == key->keycode) + return key; + + return NULL; +} + +static void acpi_topstar_notify(struct acpi_device *device, u32 event) +{ + struct tps_key_entry *key; + static bool dup_evnt[2]; + bool *dup; + struct topstar_hkey *hkey = acpi_driver_data(device); + + /* 0x83 and 0x84 key events comes duplicated... */ + if (event == 0x83 || event == 0x84) { + dup = &dup_evnt[event - 0x83]; + if (*dup) { + *dup = false; + return; + } + *dup = true; + } + + /* + * 'G key' generate two event codes, convert to only + * one event/key code for now (3G switch?) + */ + if (event == 0x97) + event = 0x96; + + key = tps_get_key_by_scancode(event); + if (key) { + input_report_key(hkey->inputdev, key->keycode, 1); + input_sync(hkey->inputdev); + input_report_key(hkey->inputdev, key->keycode, 0); + input_sync(hkey->inputdev); + return; + } + + /* Known non hotkey events don't handled or that we don't care yet */ + if (event == 0x8e || event == 0x8f || event == 0x90) + return; + + pr_info("unknown event = 0x%02x\n", event); +} + +static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state) +{ + acpi_status status; + union acpi_object fncx_params[1] = { + { .type = ACPI_TYPE_INTEGER } + }; + struct acpi_object_list fncx_arg_list = { 1, &fncx_params[0] }; + + fncx_params[0].integer.value = state ? 0x86 : 0x87; + status = acpi_evaluate_object(device->handle, "FNCX", &fncx_arg_list, NULL); + if (ACPI_FAILURE(status)) { + pr_err("Unable to switch FNCX notifications\n"); + return -ENODEV; + } + + return 0; +} + +static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode) +{ + struct tps_key_entry *key = tps_get_key_by_scancode(scancode); + + if (!key) + return -EINVAL; + + *keycode = key->keycode; + return 0; +} + +static int topstar_setkeycode(struct input_dev *dev, int scancode, int keycode) +{ + struct tps_key_entry *key; + int old_keycode; + + if (keycode < 0 || keycode > KEY_MAX) + return -EINVAL; + + key = tps_get_key_by_scancode(scancode); + + if (!key) + return -EINVAL; + + old_keycode = key->keycode; + key->keycode = keycode; + set_bit(keycode, dev->keybit); + if (!tps_get_key_by_keycode(old_keycode)) + clear_bit(old_keycode, dev->keybit); + return 0; +} + +static int acpi_topstar_init_hkey(struct topstar_hkey *hkey) +{ + struct tps_key_entry *key; + + hkey->inputdev = input_allocate_device(); + if (!hkey->inputdev) { + pr_err("Unable to allocate input device\n"); + return -ENODEV; + } + hkey->inputdev->name = "Topstar Laptop extra buttons"; + hkey->inputdev->phys = "topstar/input0"; + hkey->inputdev->id.bustype = BUS_HOST; + hkey->inputdev->getkeycode = topstar_getkeycode; + hkey->inputdev->setkeycode = topstar_setkeycode; + for (key = topstar_keymap; key->code; key++) { + set_bit(EV_KEY, hkey->inputdev->evbit); + set_bit(key->keycode, hkey->inputdev->keybit); + } + if (input_register_device(hkey->inputdev)) { + pr_err("Unable to register input device\n"); + input_free_device(hkey->inputdev); + return -ENODEV; + } + + return 0; +} + +static int acpi_topstar_add(struct acpi_device *device) +{ + struct topstar_hkey *tps_hkey; + + tps_hkey = kzalloc(sizeof(struct topstar_hkey), GFP_KERNEL); + if (!tps_hkey) + return -ENOMEM; + + strcpy(acpi_device_name(device), "Topstar TPSACPI"); + strcpy(acpi_device_class(device), ACPI_TOPSTAR_CLASS); + + if (acpi_topstar_fncx_switch(device, true)) + goto add_err; + + if (acpi_topstar_init_hkey(tps_hkey)) + goto add_err; + + device->driver_data = tps_hkey; + return 0; + +add_err: + kfree(tps_hkey); + return -ENODEV; +} + +static int acpi_topstar_remove(struct acpi_device *device, int type) +{ + struct topstar_hkey *tps_hkey = acpi_driver_data(device); + + acpi_topstar_fncx_switch(device, false); + + input_unregister_device(tps_hkey->inputdev); + kfree(tps_hkey); + + return 0; +} + +static const struct acpi_device_id topstar_device_ids[] = { + { "TPSACPI01", 0 }, + { "", 0 }, +}; +MODULE_DEVICE_TABLE(acpi, topstar_device_ids); + +static struct acpi_driver acpi_topstar_driver = { + .name = "Topstar laptop ACPI driver", + .class = ACPI_TOPSTAR_CLASS, + .ids = topstar_device_ids, + .ops = { + .add = acpi_topstar_add, + .remove = acpi_topstar_remove, + .notify = acpi_topstar_notify, + }, +}; + +static int __init topstar_laptop_init(void) +{ + int ret; + + ret = acpi_bus_register_driver(&acpi_topstar_driver); + if (ret < 0) + return ret; + + printk(KERN_INFO "Topstar Laptop ACPI extras driver loaded\n"); + + return 0; +} + +static void __exit topstar_laptop_exit(void) +{ + acpi_bus_unregister_driver(&acpi_topstar_driver); +} + +module_init(topstar_laptop_init); +module_exit(topstar_laptop_exit); + +MODULE_AUTHOR("Herton Ronaldo Krzesinski"); +MODULE_DESCRIPTION("Topstar Laptop ACPI Extras driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From de584afa5e188a2da484bb5373d449598cdb9f5e Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 18 Sep 2009 12:41:09 -0700 Subject: hwmon driver for ACPI 4.0 power meters This driver exposes ACPI 4.0 compliant power meters as hardware monitoring devices. This second revision of the driver also exports the ACPI string info as sysfs attributes, a list of the devices that the meter measures, and will send ACPI notifications over the ACPI netlink socket. This latest revision only enables the power capping controls if it can be confirmed that the power cap can be enforced by the hardware and explains how the notification interfaces work. [akpm@linux-foundation.org: remove default-y] [akpm@linux-foundation.org: build fix] Signed-off-by: Darrick J. Wong Cc: Zhang Rui Cc: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- Documentation/hwmon/acpi_power_meter | 51 ++ drivers/acpi/Kconfig | 11 + drivers/acpi/Makefile | 1 + drivers/acpi/power_meter.c | 1018 ++++++++++++++++++++++++++++++++++ 4 files changed, 1081 insertions(+) create mode 100644 Documentation/hwmon/acpi_power_meter create mode 100644 drivers/acpi/power_meter.c (limited to 'drivers') diff --git a/Documentation/hwmon/acpi_power_meter b/Documentation/hwmon/acpi_power_meter new file mode 100644 index 000000000000..c80399a00c50 --- /dev/null +++ b/Documentation/hwmon/acpi_power_meter @@ -0,0 +1,51 @@ +Kernel driver power_meter +========================= + +This driver talks to ACPI 4.0 power meters. + +Supported systems: + * Any recent system with ACPI 4.0. + Prefix: 'power_meter' + Datasheet: http://acpi.info/, section 10.4. + +Author: Darrick J. Wong + +Description +----------- + +This driver implements sensor reading support for the power meters exposed in +the ACPI 4.0 spec (Chapter 10.4). These devices have a simple set of +features--a power meter that returns average power use over a configurable +interval, an optional capping mechanism, and a couple of trip points. The +sysfs interface conforms with the specification outlined in the "Power" section +of Documentation/hwmon/sysfs-interface. + +Special Features +---------------- + +The power[1-*]_is_battery knob indicates if the power supply is a battery. +Both power[1-*]_average_{min,max} must be set before the trip points will work. +When both of them are set, an ACPI event will be broadcast on the ACPI netlink +socket and a poll notification will be sent to the appropriate +power[1-*]_average sysfs file. + +The power[1-*]_{model_number, serial_number, oem_info} fields display arbitrary +strings that ACPI provides with the meter. The measures/ directory contains +symlinks to the devices that this meter measures. + +Some computers have the ability to enforce a power cap in hardware. If this is +the case, the power[1-*]_cap and related sysfs files will appear. When the +average power consumption exceeds the cap, an ACPI event will be broadcast on +the netlink event socket and a poll notification will be sent to the +appropriate power[1-*]_alarm file to indicate that capping has begun, and the +hardware has taken action to reduce power consumption. Most likely this will +result in reduced performance. + +There are a few other ACPI notifications that can be sent by the firmware. In +all cases the ACPI event will be broadcast on the ACPI netlink event socket as +well as sent as a poll notification to a sysfs file. The events are as +follows: + +power[1-*]_cap will be notified if the firmware changes the power cap. +power[1-*]_interval will be notified if the firmware changes the averaging +interval. diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 7ec7d88c5999..2c1cab5642ff 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -82,6 +82,17 @@ config ACPI_PROCFS_POWER Say N to delete power /proc/acpi/ directories that have moved to /sys/ +config ACPI_POWER_METER + tristate "ACPI 4.0 power meter" + depends on HWMON + help + This driver exposes ACPI 4.0 power meters as hardware monitoring + devices. Say Y (or M) if you have a computer with ACPI 4.0 firmware + and a power meter. + + To compile this driver as a module, choose M here: + the module will be called power-meter. + config ACPI_SYSFS_POWER bool "Future power /sys interface" select POWER_SUPPLY diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 03a985be3fe3..82cd49dc603b 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbs.o +obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o # processor has its own "processor." module_param namespace processor-y := processor_core.o processor_throttling.o diff --git a/drivers/acpi/power_meter.c b/drivers/acpi/power_meter.c new file mode 100644 index 000000000000..e6bfd77986b8 --- /dev/null +++ b/drivers/acpi/power_meter.c @@ -0,0 +1,1018 @@ +/* + * A hwmon driver for ACPI 4.0 power meters + * Copyright (C) 2009 IBM + * + * Author: Darrick J. Wong + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACPI_POWER_METER_NAME "power_meter" +ACPI_MODULE_NAME(ACPI_POWER_METER_NAME); +#define ACPI_POWER_METER_DEVICE_NAME "Power Meter" +#define ACPI_POWER_METER_CLASS "power_meter_resource" + +#define NUM_SENSORS 17 + +#define POWER_METER_CAN_MEASURE (1 << 0) +#define POWER_METER_CAN_TRIP (1 << 1) +#define POWER_METER_CAN_CAP (1 << 2) +#define POWER_METER_CAN_NOTIFY (1 << 3) +#define POWER_METER_IS_BATTERY (1 << 8) +#define UNKNOWN_HYSTERESIS 0xFFFFFFFF + +#define METER_NOTIFY_CONFIG 0x80 +#define METER_NOTIFY_TRIP 0x81 +#define METER_NOTIFY_CAP 0x82 +#define METER_NOTIFY_CAPPING 0x83 +#define METER_NOTIFY_INTERVAL 0x84 + +#define POWER_AVERAGE_NAME "power1_average" +#define POWER_CAP_NAME "power1_cap" +#define POWER_AVG_INTERVAL_NAME "power1_average_interval" +#define POWER_ALARM_NAME "power1_alarm" + +static int cap_in_hardware; +static int force_cap_on; + +static int can_cap_in_hardware(void) +{ + return force_cap_on || cap_in_hardware; +} + +static struct acpi_device_id power_meter_ids[] = { + {"ACPI000D", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, power_meter_ids); + +struct acpi_power_meter_capabilities { + acpi_integer flags; + acpi_integer units; + acpi_integer type; + acpi_integer accuracy; + acpi_integer sampling_time; + acpi_integer min_avg_interval; + acpi_integer max_avg_interval; + acpi_integer hysteresis; + acpi_integer configurable_cap; + acpi_integer min_cap; + acpi_integer max_cap; +}; + +struct acpi_power_meter_resource { + struct acpi_device *acpi_dev; + acpi_bus_id name; + struct mutex lock; + struct device *hwmon_dev; + struct acpi_power_meter_capabilities caps; + acpi_string model_number; + acpi_string serial_number; + acpi_string oem_info; + acpi_integer power; + acpi_integer cap; + acpi_integer avg_interval; + int sensors_valid; + unsigned long sensors_last_updated; + struct sensor_device_attribute sensors[NUM_SENSORS]; + int num_sensors; + int trip[2]; + int num_domain_devices; + struct acpi_device **domain_devices; + struct kobject *holders_dir; +}; + +struct ro_sensor_template { + char *label; + ssize_t (*show)(struct device *dev, + struct device_attribute *devattr, + char *buf); + int index; +}; + +struct rw_sensor_template { + char *label; + ssize_t (*show)(struct device *dev, + struct device_attribute *devattr, + char *buf); + ssize_t (*set)(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count); + int index; +}; + +/* Averaging interval */ +static int update_avg_interval(struct acpi_power_meter_resource *resource) +{ + unsigned long long data; + acpi_status status; + + status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GAI", + NULL, &data); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GAI")); + return -ENODEV; + } + + resource->avg_interval = data; + return 0; +} + +static ssize_t show_avg_interval(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + + mutex_lock(&resource->lock); + update_avg_interval(resource); + mutex_unlock(&resource->lock); + + return sprintf(buf, "%llu\n", resource->avg_interval); +} + +static ssize_t set_avg_interval(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + struct acpi_object_list args = { 1, &arg0 }; + int res; + unsigned long temp; + unsigned long long data; + acpi_status status; + + res = strict_strtoul(buf, 10, &temp); + if (res) + return res; + + if (temp > resource->caps.max_avg_interval || + temp < resource->caps.min_avg_interval) + return -EINVAL; + arg0.integer.value = temp; + + mutex_lock(&resource->lock); + status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PAI", + &args, &data); + if (!ACPI_FAILURE(status)) + resource->avg_interval = temp; + mutex_unlock(&resource->lock); + + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PAI")); + return -EINVAL; + } + + /* _PAI returns 0 on success, nonzero otherwise */ + if (data) + return -EINVAL; + + return count; +} + +/* Cap functions */ +static int update_cap(struct acpi_power_meter_resource *resource) +{ + unsigned long long data; + acpi_status status; + + status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GHL", + NULL, &data); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GHL")); + return -ENODEV; + } + + resource->cap = data; + return 0; +} + +static ssize_t show_cap(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + + mutex_lock(&resource->lock); + update_cap(resource); + mutex_unlock(&resource->lock); + + return sprintf(buf, "%llu\n", resource->cap * 1000); +} + +static ssize_t set_cap(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + struct acpi_object_list args = { 1, &arg0 }; + int res; + unsigned long temp; + unsigned long long data; + acpi_status status; + + res = strict_strtoul(buf, 10, &temp); + if (res) + return res; + + temp /= 1000; + if (temp > resource->caps.max_cap || temp < resource->caps.min_cap) + return -EINVAL; + arg0.integer.value = temp; + + mutex_lock(&resource->lock); + status = acpi_evaluate_integer(resource->acpi_dev->handle, "_SHL", + &args, &data); + if (!ACPI_FAILURE(status)) + resource->cap = temp; + mutex_unlock(&resource->lock); + + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SHL")); + return -EINVAL; + } + + /* _SHL returns 0 on success, nonzero otherwise */ + if (data) + return -EINVAL; + + return count; +} + +/* Power meter trip points */ +static int set_acpi_trip(struct acpi_power_meter_resource *resource) +{ + union acpi_object arg_objs[] = { + {ACPI_TYPE_INTEGER}, + {ACPI_TYPE_INTEGER} + }; + struct acpi_object_list args = { 2, arg_objs }; + unsigned long long data; + acpi_status status; + + /* Both trip levels must be set */ + if (resource->trip[0] < 0 || resource->trip[1] < 0) + return 0; + + /* This driver stores min, max; ACPI wants max, min. */ + arg_objs[0].integer.value = resource->trip[1]; + arg_objs[1].integer.value = resource->trip[0]; + + status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PTP", + &args, &data); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTP")); + return -EINVAL; + } + + return data; +} + +static ssize_t set_trip(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + int res; + unsigned long temp; + + res = strict_strtoul(buf, 10, &temp); + if (res) + return res; + + temp /= 1000; + if (temp < 0) + return -EINVAL; + + mutex_lock(&resource->lock); + resource->trip[attr->index - 7] = temp; + res = set_acpi_trip(resource); + mutex_unlock(&resource->lock); + + if (res) + return res; + + return count; +} + +/* Power meter */ +static int update_meter(struct acpi_power_meter_resource *resource) +{ + unsigned long long data; + acpi_status status; + unsigned long local_jiffies = jiffies; + + if (time_before(local_jiffies, resource->sensors_last_updated + + msecs_to_jiffies(resource->caps.sampling_time)) && + resource->sensors_valid) + return 0; + + status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM", + NULL, &data); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMM")); + return -ENODEV; + } + + resource->power = data; + resource->sensors_valid = 1; + resource->sensors_last_updated = jiffies; + return 0; +} + +static ssize_t show_power(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + + mutex_lock(&resource->lock); + update_meter(resource); + mutex_unlock(&resource->lock); + + return sprintf(buf, "%llu\n", resource->power * 1000); +} + +/* Miscellaneous */ +static ssize_t show_str(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + acpi_string val; + + switch (attr->index) { + case 0: + val = resource->model_number; + break; + case 1: + val = resource->serial_number; + break; + case 2: + val = resource->oem_info; + break; + default: + BUG(); + } + + return sprintf(buf, "%s\n", val); +} + +static ssize_t show_val(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + acpi_integer val = 0; + + switch (attr->index) { + case 0: + val = resource->caps.min_avg_interval; + break; + case 1: + val = resource->caps.max_avg_interval; + break; + case 2: + val = resource->caps.min_cap * 1000; + break; + case 3: + val = resource->caps.max_cap * 1000; + break; + case 4: + if (resource->caps.hysteresis == UNKNOWN_HYSTERESIS) + return sprintf(buf, "unknown\n"); + + val = resource->caps.hysteresis * 1000; + break; + case 5: + if (resource->caps.flags & POWER_METER_IS_BATTERY) + val = 1; + else + val = 0; + break; + case 6: + if (resource->power > resource->cap) + val = 1; + else + val = 0; + break; + case 7: + case 8: + if (resource->trip[attr->index - 7] < 0) + return sprintf(buf, "unknown\n"); + + val = resource->trip[attr->index - 7] * 1000; + break; + default: + BUG(); + } + + return sprintf(buf, "%llu\n", val); +} + +static ssize_t show_accuracy(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + unsigned int acc = resource->caps.accuracy; + + return sprintf(buf, "%u.%u%%\n", acc / 1000, acc % 1000); +} + +static ssize_t show_name(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME); +} + +/* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */ +static struct ro_sensor_template meter_ro_attrs[] = { +{POWER_AVERAGE_NAME, show_power, 0}, +{"power1_accuracy", show_accuracy, 0}, +{"power1_average_interval_min", show_val, 0}, +{"power1_average_interval_max", show_val, 1}, +{"power1_is_battery", show_val, 5}, +{NULL, NULL, 0}, +}; + +static struct rw_sensor_template meter_rw_attrs[] = { +{POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0}, +{NULL, NULL, NULL, 0}, +}; + +static struct ro_sensor_template misc_cap_attrs[] = { +{"power1_cap_min", show_val, 2}, +{"power1_cap_max", show_val, 3}, +{"power1_cap_hyst", show_val, 4}, +{POWER_ALARM_NAME, show_val, 6}, +{NULL, NULL, 0}, +}; + +static struct ro_sensor_template ro_cap_attrs[] = { +{POWER_CAP_NAME, show_cap, 0}, +{NULL, NULL, 0}, +}; + +static struct rw_sensor_template rw_cap_attrs[] = { +{POWER_CAP_NAME, show_cap, set_cap, 0}, +{NULL, NULL, NULL, 0}, +}; + +static struct rw_sensor_template trip_attrs[] = { +{"power1_average_min", show_val, set_trip, 7}, +{"power1_average_max", show_val, set_trip, 8}, +{NULL, NULL, NULL, 0}, +}; + +static struct ro_sensor_template misc_attrs[] = { +{"name", show_name, 0}, +{"power1_model_number", show_str, 0}, +{"power1_oem_info", show_str, 2}, +{"power1_serial_number", show_str, 1}, +{NULL, NULL, 0}, +}; + +/* Read power domain data */ +static void remove_domain_devices(struct acpi_power_meter_resource *resource) +{ + int i; + + if (!resource->num_domain_devices) + return; + + for (i = 0; i < resource->num_domain_devices; i++) { + struct acpi_device *obj = resource->domain_devices[i]; + if (!obj) + continue; + + sysfs_remove_link(resource->holders_dir, + kobject_name(&obj->dev.kobj)); + put_device(&obj->dev); + } + + kfree(resource->domain_devices); + kobject_put(resource->holders_dir); +} + +static int read_domain_devices(struct acpi_power_meter_resource *resource) +{ + int res = 0; + int i; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *pss; + acpi_status status; + + status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMD", NULL, + &buffer); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMD")); + return -ENODEV; + } + + pss = buffer.pointer; + if (!pss || + pss->type != ACPI_TYPE_PACKAGE) { + dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME + "Invalid _PMD data\n"); + res = -EFAULT; + goto end; + } + + if (!pss->package.count) + goto end; + + resource->domain_devices = kzalloc(sizeof(struct acpi_device *) * + pss->package.count, GFP_KERNEL); + if (!resource->domain_devices) { + res = -ENOMEM; + goto end; + } + + resource->holders_dir = kobject_create_and_add("measures", + &resource->acpi_dev->dev.kobj); + if (!resource->holders_dir) { + res = -ENOMEM; + goto exit_free; + } + + resource->num_domain_devices = pss->package.count; + + for (i = 0; i < pss->package.count; i++) { + struct acpi_device *obj; + union acpi_object *element = &(pss->package.elements[i]); + + /* Refuse non-references */ + if (element->type != ACPI_TYPE_LOCAL_REFERENCE) + continue; + + /* Create a symlink to domain objects */ + resource->domain_devices[i] = NULL; + status = acpi_bus_get_device(element->reference.handle, + &resource->domain_devices[i]); + if (ACPI_FAILURE(status)) + continue; + + obj = resource->domain_devices[i]; + get_device(&obj->dev); + + res = sysfs_create_link(resource->holders_dir, &obj->dev.kobj, + kobject_name(&obj->dev.kobj)); + if (res) { + put_device(&obj->dev); + resource->domain_devices[i] = NULL; + } + } + + res = 0; + goto end; + +exit_free: + kfree(resource->domain_devices); +end: + kfree(buffer.pointer); + return res; +} + +/* Registration and deregistration */ +static int register_ro_attrs(struct acpi_power_meter_resource *resource, + struct ro_sensor_template *ro) +{ + struct device *dev = &resource->acpi_dev->dev; + struct sensor_device_attribute *sensors = + &resource->sensors[resource->num_sensors]; + int res = 0; + + while (ro->label) { + sensors->dev_attr.attr.name = ro->label; + sensors->dev_attr.attr.mode = S_IRUGO; + sensors->dev_attr.show = ro->show; + sensors->index = ro->index; + + res = device_create_file(dev, &sensors->dev_attr); + if (res) { + sensors->dev_attr.attr.name = NULL; + goto error; + } + sensors++; + resource->num_sensors++; + ro++; + } + +error: + return res; +} + +static int register_rw_attrs(struct acpi_power_meter_resource *resource, + struct rw_sensor_template *rw) +{ + struct device *dev = &resource->acpi_dev->dev; + struct sensor_device_attribute *sensors = + &resource->sensors[resource->num_sensors]; + int res = 0; + + while (rw->label) { + sensors->dev_attr.attr.name = rw->label; + sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR; + sensors->dev_attr.show = rw->show; + sensors->dev_attr.store = rw->set; + sensors->index = rw->index; + + res = device_create_file(dev, &sensors->dev_attr); + if (res) { + sensors->dev_attr.attr.name = NULL; + goto error; + } + sensors++; + resource->num_sensors++; + rw++; + } + +error: + return res; +} + +static void remove_attrs(struct acpi_power_meter_resource *resource) +{ + int i; + + for (i = 0; i < resource->num_sensors; i++) { + if (!resource->sensors[i].dev_attr.attr.name) + continue; + device_remove_file(&resource->acpi_dev->dev, + &resource->sensors[i].dev_attr); + } + + remove_domain_devices(resource); + + resource->num_sensors = 0; +} + +static int setup_attrs(struct acpi_power_meter_resource *resource) +{ + int res = 0; + + res = read_domain_devices(resource); + if (res) + return res; + + if (resource->caps.flags & POWER_METER_CAN_MEASURE) { + res = register_ro_attrs(resource, meter_ro_attrs); + if (res) + goto error; + res = register_rw_attrs(resource, meter_rw_attrs); + if (res) + goto error; + } + + if (resource->caps.flags & POWER_METER_CAN_CAP) { + if (!can_cap_in_hardware()) { + dev_err(&resource->acpi_dev->dev, + "Ignoring unsafe software power cap!\n"); + goto skip_unsafe_cap; + } + + if (resource->caps.configurable_cap) { + res = register_rw_attrs(resource, rw_cap_attrs); + if (res) + goto error; + } else { + res = register_ro_attrs(resource, ro_cap_attrs); + if (res) + goto error; + } + res = register_ro_attrs(resource, misc_cap_attrs); + if (res) + goto error; + } +skip_unsafe_cap: + + if (resource->caps.flags & POWER_METER_CAN_TRIP) { + res = register_rw_attrs(resource, trip_attrs); + if (res) + goto error; + } + + res = register_ro_attrs(resource, misc_attrs); + if (res) + goto error; + + return res; +error: + remove_domain_devices(resource); + remove_attrs(resource); + return res; +} + +static void free_capabilities(struct acpi_power_meter_resource *resource) +{ + acpi_string *str; + int i; + + str = &resource->model_number; + for (i = 0; i < 3; i++, str++) + kfree(*str); +} + +static int read_capabilities(struct acpi_power_meter_resource *resource) +{ + int res = 0; + int i; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer state = { 0, NULL }; + struct acpi_buffer format = { sizeof("NNNNNNNNNNN"), "NNNNNNNNNNN" }; + union acpi_object *pss; + acpi_string *str; + acpi_status status; + + status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMC", NULL, + &buffer); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMC")); + return -ENODEV; + } + + pss = buffer.pointer; + if (!pss || + pss->type != ACPI_TYPE_PACKAGE || + pss->package.count != 14) { + dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME + "Invalid _PMC data\n"); + res = -EFAULT; + goto end; + } + + /* Grab all the integer data at once */ + state.length = sizeof(struct acpi_power_meter_capabilities); + state.pointer = &resource->caps; + + status = acpi_extract_package(pss, &format, &state); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Invalid data")); + res = -EFAULT; + goto end; + } + + if (resource->caps.units) { + dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME + "Unknown units %llu.\n", + resource->caps.units); + res = -EINVAL; + goto end; + } + + /* Grab the string data */ + str = &resource->model_number; + + for (i = 11; i < 14; i++) { + union acpi_object *element = &(pss->package.elements[i]); + + if (element->type != ACPI_TYPE_STRING) { + res = -EINVAL; + goto error; + } + + *str = kzalloc(sizeof(u8) * (element->string.length + 1), + GFP_KERNEL); + if (!*str) { + res = -ENOMEM; + goto error; + } + + strncpy(*str, element->string.pointer, element->string.length); + str++; + } + + dev_info(&resource->acpi_dev->dev, "Found ACPI power meter.\n"); + goto end; +error: + str = &resource->model_number; + for (i = 0; i < 3; i++, str++) + kfree(*str); +end: + kfree(buffer.pointer); + return res; +} + +/* Handle ACPI event notifications */ +static void acpi_power_meter_notify(struct acpi_device *device, u32 event) +{ + struct acpi_power_meter_resource *resource; + int res; + + if (!device || !acpi_driver_data(device)) + return; + + resource = acpi_driver_data(device); + + mutex_lock(&resource->lock); + switch (event) { + case METER_NOTIFY_CONFIG: + free_capabilities(resource); + res = read_capabilities(resource); + if (res) + break; + + remove_attrs(resource); + setup_attrs(resource); + break; + case METER_NOTIFY_TRIP: + sysfs_notify(&device->dev.kobj, NULL, POWER_AVERAGE_NAME); + update_meter(resource); + break; + case METER_NOTIFY_CAP: + sysfs_notify(&device->dev.kobj, NULL, POWER_CAP_NAME); + update_cap(resource); + break; + case METER_NOTIFY_INTERVAL: + sysfs_notify(&device->dev.kobj, NULL, POWER_AVG_INTERVAL_NAME); + update_avg_interval(resource); + break; + case METER_NOTIFY_CAPPING: + sysfs_notify(&device->dev.kobj, NULL, POWER_ALARM_NAME); + dev_info(&device->dev, "Capping in progress.\n"); + break; + default: + BUG(); + } + mutex_unlock(&resource->lock); + + acpi_bus_generate_netlink_event(ACPI_POWER_METER_CLASS, + dev_name(&device->dev), event, 0); +} + +static int acpi_power_meter_add(struct acpi_device *device) +{ + int res; + struct acpi_power_meter_resource *resource; + + if (!device) + return -EINVAL; + + resource = kzalloc(sizeof(struct acpi_power_meter_resource), + GFP_KERNEL); + if (!resource) + return -ENOMEM; + + resource->sensors_valid = 0; + resource->acpi_dev = device; + mutex_init(&resource->lock); + strcpy(acpi_device_name(device), ACPI_POWER_METER_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_POWER_METER_CLASS); + device->driver_data = resource; + + free_capabilities(resource); + res = read_capabilities(resource); + if (res) + goto exit_free; + + resource->trip[0] = resource->trip[1] = -1; + + res = setup_attrs(resource); + if (res) + goto exit_free; + + resource->hwmon_dev = hwmon_device_register(&device->dev); + if (IS_ERR(resource->hwmon_dev)) { + res = PTR_ERR(resource->hwmon_dev); + goto exit_remove; + } + + res = 0; + goto exit; + +exit_remove: + remove_attrs(resource); +exit_free: + kfree(resource); +exit: + return res; +} + +static int acpi_power_meter_remove(struct acpi_device *device, int type) +{ + struct acpi_power_meter_resource *resource; + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + resource = acpi_driver_data(device); + hwmon_device_unregister(resource->hwmon_dev); + + free_capabilities(resource); + remove_attrs(resource); + + kfree(resource); + return 0; +} + +static int acpi_power_meter_resume(struct acpi_device *device) +{ + struct acpi_power_meter_resource *resource; + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + resource = acpi_driver_data(device); + free_capabilities(resource); + read_capabilities(resource); + + return 0; +} + +static struct acpi_driver acpi_power_meter_driver = { + .name = "power_meter", + .class = ACPI_POWER_METER_CLASS, + .ids = power_meter_ids, + .ops = { + .add = acpi_power_meter_add, + .remove = acpi_power_meter_remove, + .resume = acpi_power_meter_resume, + .notify = acpi_power_meter_notify, + }, +}; + +/* Module init/exit routines */ +static int __init enable_cap_knobs(const struct dmi_system_id *d) +{ + cap_in_hardware = 1; + return 0; +} + +static struct dmi_system_id __initdata pm_dmi_table[] = { + { + enable_cap_knobs, "IBM Active Energy Manager", + { + DMI_MATCH(DMI_SYS_VENDOR, "IBM") + }, + }, + {} +}; + +static int __init acpi_power_meter_init(void) +{ + int result; + + if (acpi_disabled) + return -ENODEV; + + dmi_check_system(pm_dmi_table); + + result = acpi_bus_register_driver(&acpi_power_meter_driver); + if (result < 0) + return -ENODEV; + + return 0; +} + +static void __exit acpi_power_meter_exit(void) +{ + acpi_bus_unregister_driver(&acpi_power_meter_driver); +} + +MODULE_AUTHOR("Darrick J. Wong "); +MODULE_DESCRIPTION("ACPI 4.0 power meter driver"); +MODULE_LICENSE("GPL"); + +module_param(force_cap_on, bool, 0644); +MODULE_PARM_DESC(force_cap_on, "Enable power cap even it is unsafe to do so."); + +module_init(acpi_power_meter_init); +module_exit(acpi_power_meter_exit); -- cgit v1.2.3-59-g8ed1b From eb27cae8adaa658a0bf31631baa1ce29d8183759 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 6 Jul 2009 23:40:19 -0400 Subject: ACPI: linux/acpi.h should not include linux/dmi.h users of acpi.h that need dmi.h should include it directly. Signed-off-by: Len Brown --- drivers/acpi/bus.c | 1 + drivers/acpi/ec.c | 1 + drivers/acpi/pci_slot.c | 1 + drivers/acpi/video.c | 2 +- drivers/pci/dmar.c | 1 + include/linux/acpi.h | 2 -- 6 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2876fc70c3a9..0fb6b2a8b103 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "internal.h" diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 391f331674c7..c434f6571ab8 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -42,6 +42,7 @@ #include #include #include +#include #define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_DEVICE_NAME "Embedded Controller" diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 12158e0d009b..7aa6802c0ee3 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -31,6 +31,7 @@ #include #include #include +#include static int debug; static int check_sta_before_sun; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 60ea984c84a0..055a455b6c75 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -40,7 +40,7 @@ #include #include #include - +#include #include #include diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 7b287cb38b7a..4484ac089772 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -33,6 +33,7 @@ #include #include #include +#include #undef PREFIX #define PREFIX "DMAR:" diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 34321cfffeab..7950c65c43af 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -41,8 +41,6 @@ #include #include #include -#include - enum acpi_irq_model_id { ACPI_IRQ_MODEL_PIC = 0, -- cgit v1.2.3-59-g8ed1b From 09729f0b11a389e046f621f3e4841043f460b603 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 14 Sep 2009 12:43:51 +0200 Subject: hp-wmi: fix rfkill memory leak on unload rfkill_unregister() should always be followed by rfkill_destroy() In this case, rfkill_destroy was called two times on wifi_rfkill and never on bluetooth_rfkill. Signed-off-by: Corentin Chary Acked-by: Matthew Garrett Signed-off-by: Len Brown --- drivers/platform/x86/hp-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index a2ad53e15874..a750192d6d4f 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -502,7 +502,7 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) } if (bluetooth_rfkill) { rfkill_unregister(bluetooth_rfkill); - rfkill_destroy(wifi_rfkill); + rfkill_destroy(bluetooth_rfkill); } if (wwan_rfkill) { rfkill_unregister(wwan_rfkill); -- cgit v1.2.3-59-g8ed1b From 7d7decb213a65dea0973ed980c02dae2b1b88dbe Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 18 Sep 2009 12:41:08 -0700 Subject: acpi: switch /proc/acpi/{debug_layer,debug_level} to seq_file Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/debug.c | 82 ++++++++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index a8287be0870e..8a690c3b8e23 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -3,6 +3,7 @@ */ #include +#include #include #include #include @@ -201,72 +202,54 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state, #define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" #define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" -static int -acpi_system_read_debug(char *page, - char **start, off_t off, int count, int *eof, void *data) +static int acpi_system_debug_proc_show(struct seq_file *m, void *v) { - char *p = page; - int size = 0; unsigned int i; - if (off != 0) - goto end; + seq_printf(m, "%-25s\tHex SET\n", "Description"); - p += sprintf(p, "%-25s\tHex SET\n", "Description"); - - switch ((unsigned long)data) { + switch ((unsigned long)m->private) { case 0: for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) { - p += sprintf(p, "%-25s\t0x%08lX [%c]\n", + seq_printf(m, "%-25s\t0x%08lX [%c]\n", acpi_debug_layers[i].name, acpi_debug_layers[i].value, (acpi_dbg_layer & acpi_debug_layers[i]. value) ? '*' : ' '); } - p += sprintf(p, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", + seq_printf(m, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", ACPI_ALL_DRIVERS, (acpi_dbg_layer & ACPI_ALL_DRIVERS) == ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 0 ? ' ' : '-'); - p += sprintf(p, + seq_printf(m, "--\ndebug_layer = 0x%08X (* = enabled, - = partial)\n", acpi_dbg_layer); break; case 1: for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) { - p += sprintf(p, "%-25s\t0x%08lX [%c]\n", + seq_printf(m, "%-25s\t0x%08lX [%c]\n", acpi_debug_levels[i].name, acpi_debug_levels[i].value, (acpi_dbg_level & acpi_debug_levels[i]. value) ? '*' : ' '); } - p += sprintf(p, "--\ndebug_level = 0x%08X (* = enabled)\n", + seq_printf(m, "--\ndebug_level = 0x%08X (* = enabled)\n", acpi_dbg_level); break; - default: - p += sprintf(p, "Invalid debug option\n"); - break; } + return 0; +} - end: - size = (p - page); - if (size <= off + count) - *eof = 1; - *start = page + off; - size -= off; - if (size > count) - size = count; - if (size < 0) - size = 0; - - return size; +static int acpi_system_debug_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, acpi_system_debug_proc_show, PDE(inode)->data); } -static int -acpi_system_write_debug(struct file *file, +static ssize_t acpi_system_debug_proc_write(struct file *file, const char __user * buffer, - unsigned long count, void *data) + size_t count, loff_t *pos) { char debug_string[12] = { '\0' }; @@ -279,7 +262,7 @@ acpi_system_write_debug(struct file *file, debug_string[count] = '\0'; - switch ((unsigned long)data) { + switch ((unsigned long)PDE(file->f_path.dentry->d_inode)->data) { case 0: acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0); break; @@ -292,6 +275,15 @@ acpi_system_write_debug(struct file *file, return count; } + +static const struct file_operations acpi_system_debug_proc_fops = { + .owner = THIS_MODULE, + .open = acpi_system_debug_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = acpi_system_debug_proc_write, +}; #endif int __init acpi_debug_init(void) @@ -303,24 +295,18 @@ int __init acpi_debug_init(void) /* 'debug_layer' [R/W] */ name = ACPI_SYSTEM_FILE_DEBUG_LAYER; - entry = - create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir, acpi_system_read_debug, - (void *)0); - if (entry) - entry->write_proc = acpi_system_write_debug; - else + entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_debug_proc_fops, + (void *)0); + if (!entry) goto Error; /* 'debug_level' [R/W] */ name = ACPI_SYSTEM_FILE_DEBUG_LEVEL; - entry = - create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir, acpi_system_read_debug, - (void *)1); - if (entry) - entry->write_proc = acpi_system_write_debug; - else + entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_debug_proc_fops, + (void *)1); + if (!entry) goto Error; Done: -- cgit v1.2.3-59-g8ed1b From df43176c934f2bc01f7615a6e20a4b8e77dcdd11 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 18 Sep 2009 12:41:10 -0700 Subject: thermal: add missing Kconfig dependency Otherwise THERMAL_HWMON can be selected when HWMON=n and THERMAL=n, which fails to build. Signed-off-by: Jan Beulich Cc: Zhang Rui Cc: Matthew Garrett Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index a86e952ed4ca..bf7c687519ef 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -15,6 +15,7 @@ menuconfig THERMAL config THERMAL_HWMON bool "Hardware monitoring support" + depends on THERMAL depends on HWMON=y || HWMON=THERMAL help The generic thermal sysfs driver's hardware monitoring support -- cgit v1.2.3-59-g8ed1b From ded0cdfc6a7673916b0878c32fa8ba566b4f8cdb Mon Sep 17 00:00:00 2001 From: Peter Feuerer Date: Thu, 6 Aug 2009 15:57:52 -0700 Subject: acerhdf: fix fan control for AOA150 model - Apply Borislav Petkov's patch (convert the fancmd[] array to a real struct thus disambiguating command handling and making code more readable.) - Add BIOS product to BIOS table as AOA110 and AOA150 have different register values - Add force_product parameter to allow forcing different product - fix linker warning caused by "acerhdf_drv" not being named "acerhdf_driver" Signed-off-by: Peter Feuerer Cc: Andreas Mohr Acked-by: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/platform/x86/acerhdf.c | 97 ++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index bdfee177eefb..aa298d6ea371 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -52,7 +52,7 @@ */ #undef START_IN_KERNEL_MODE -#define DRV_VER "0.5.13" +#define DRV_VER "0.5.16" /* * According to the Atom N270 datasheet, @@ -90,6 +90,7 @@ static unsigned int fanoff = 58; static unsigned int verbose; static unsigned int fanstate = ACERHDF_FAN_AUTO; static char force_bios[16]; +static char force_product[16]; static unsigned int prev_interval; struct thermal_zone_device *thz_dev; struct thermal_cooling_device *cl_dev; @@ -107,34 +108,58 @@ module_param(verbose, uint, 0600); MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); module_param_string(force_bios, force_bios, 16, 0); MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check"); +module_param_string(force_product, force_product, 16, 0); +MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); + +/* + * cmd_off: to switch the fan completely off / to check if the fan is off + * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then + * the fan speed depending on the temperature + */ +struct fancmd { + u8 cmd_off; + u8 cmd_auto; +}; /* BIOS settings */ struct bios_settings_t { const char *vendor; + const char *product; const char *version; unsigned char fanreg; unsigned char tempreg; - unsigned char fancmd[2]; /* fan off and auto commands */ + struct fancmd cmd; }; /* Register addresses and values for different BIOS versions */ static const struct bios_settings_t bios_tbl[] = { - {"Acer", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, - {"Acer", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, - {"Acer", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, - {"Acer", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, - {"Acer", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, - {"Acer", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, - {"Acer", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, - {"Acer", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, - {"Gateway", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, - {"Packard Bell", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, - {"", "", 0, 0, {0, 0} } + /* AOA110 */ + {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, + {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, + {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, + {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, + {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, + {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, + {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, + {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, + /* AOA150 */ + {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} }, + {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, + {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, + {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, + {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, + {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, + /* special BIOS / other */ + {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, + {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, + {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, + {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, + /* pewpew-terminator */ + {"", "", "", 0, 0, {0, 0} } }; static const struct bios_settings_t *bios_cfg __read_mostly; - static int acerhdf_get_temp(int *temp) { u8 read_temp; @@ -150,13 +175,14 @@ static int acerhdf_get_temp(int *temp) static int acerhdf_get_fanstate(int *state) { u8 fan; - bool tmp; if (ec_read(bios_cfg->fanreg, &fan)) return -EINVAL; - tmp = (fan == bios_cfg->fancmd[ACERHDF_FAN_OFF]); - *state = tmp ? ACERHDF_FAN_OFF : ACERHDF_FAN_AUTO; + if (fan != bios_cfg->cmd.cmd_off) + *state = ACERHDF_FAN_AUTO; + else + *state = ACERHDF_FAN_OFF; return 0; } @@ -175,7 +201,8 @@ static void acerhdf_change_fanstate(int state) state = ACERHDF_FAN_AUTO; } - cmd = bios_cfg->fancmd[state]; + cmd = (state == ACERHDF_FAN_OFF) ? bios_cfg->cmd.cmd_off + : bios_cfg->cmd.cmd_auto; fanstate = state; ec_write(bios_cfg->fanreg, cmd); @@ -437,7 +464,7 @@ static int acerhdf_remove(struct platform_device *device) return 0; } -struct platform_driver acerhdf_drv = { +static struct platform_driver acerhdf_driver = { .driver = { .name = "acerhdf", .owner = THIS_MODULE, @@ -454,32 +481,40 @@ static int acerhdf_check_hardware(void) { char const *vendor, *version, *product; int i; + unsigned long prod_len = 0; /* get BIOS data */ vendor = dmi_get_system_info(DMI_SYS_VENDOR); version = dmi_get_system_info(DMI_BIOS_VERSION); product = dmi_get_system_info(DMI_PRODUCT_NAME); + pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); - if (!force_bios[0]) { - if (strncmp(product, "AO", 2)) { - pr_err("no Aspire One hardware found\n"); - return -EINVAL; - } - } else { - pr_info("forcing BIOS version: %s\n", version); + if (force_bios[0]) { version = force_bios; + pr_info("forcing BIOS version: %s\n", version); kernelmode = 0; } + if (force_product[0]) { + product = force_product; + pr_info("forcing BIOS product: %s\n", product); + kernelmode = 0; + } + + prod_len = strlen(product); + if (verbose) pr_info("BIOS info: %s %s, product: %s\n", vendor, version, product); /* search BIOS version and vendor in BIOS settings table */ for (i = 0; bios_tbl[i].version[0]; i++) { - if (!strcmp(bios_tbl[i].vendor, vendor) && + if (strlen(bios_tbl[i].product) >= prod_len && + !strncmp(bios_tbl[i].product, product, + strlen(bios_tbl[i].product)) && + !strcmp(bios_tbl[i].vendor, vendor) && !strcmp(bios_tbl[i].version, version)) { bios_cfg = &bios_tbl[i]; break; @@ -487,8 +522,8 @@ static int acerhdf_check_hardware(void) } if (!bios_cfg) { - pr_err("unknown (unsupported) BIOS version %s/%s, " - "please report, aborting!\n", vendor, version); + pr_err("unknown (unsupported) BIOS version %s/%s/%s, " + "please report, aborting!\n", vendor, product, version); return -EINVAL; } @@ -509,7 +544,7 @@ static int acerhdf_register_platform(void) { int err = 0; - err = platform_driver_register(&acerhdf_drv); + err = platform_driver_register(&acerhdf_driver); if (err) return err; @@ -525,7 +560,7 @@ static void acerhdf_unregister_platform(void) return; platform_device_del(acerhdf_dev); - platform_driver_unregister(&acerhdf_drv); + platform_driver_unregister(&acerhdf_driver); } static int acerhdf_register_thermal(void) -- cgit v1.2.3-59-g8ed1b From ff27e1f3037535a547e2474eecb688428d654dc3 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 18 Sep 2009 12:41:05 -0700 Subject: acerhdf: convert to dev_pm_ops Signed-off-by: Borislav Petkov Signed-off-by: Peter Feuerer Cc: Andreas Mohr Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/platform/x86/acerhdf.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index aa298d6ea371..5aef16f33841 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -52,7 +52,7 @@ */ #undef START_IN_KERNEL_MODE -#define DRV_VER "0.5.16" +#define DRV_VER "0.5.17" /* * According to the Atom N270 datasheet, @@ -435,7 +435,7 @@ struct thermal_cooling_device_ops acerhdf_cooling_ops = { }; /* suspend / resume functionality */ -static int acerhdf_suspend(struct platform_device *dev, pm_message_t state) +static int acerhdf_suspend(struct device *dev) { if (kernelmode) acerhdf_change_fanstate(ACERHDF_FAN_AUTO); @@ -446,14 +446,6 @@ static int acerhdf_suspend(struct platform_device *dev, pm_message_t state) return 0; } -static int acerhdf_resume(struct platform_device *device) -{ - if (verbose) - pr_notice("resuming\n"); - - return 0; -} - static int __devinit acerhdf_probe(struct platform_device *device) { return 0; @@ -464,15 +456,19 @@ static int acerhdf_remove(struct platform_device *device) return 0; } +static struct dev_pm_ops acerhdf_pm_ops = { + .suspend = acerhdf_suspend, + .freeze = acerhdf_suspend, +}; + static struct platform_driver acerhdf_driver = { .driver = { - .name = "acerhdf", + .name = "acerhdf", .owner = THIS_MODULE, + .pm = &acerhdf_pm_ops, }, .probe = acerhdf_probe, .remove = acerhdf_remove, - .suspend = acerhdf_suspend, - .resume = acerhdf_resume, }; -- cgit v1.2.3-59-g8ed1b From f944915187f53810130eb1c56985e27e3cbe4a6d Mon Sep 17 00:00:00 2001 From: Peter Feuerer Date: Fri, 18 Sep 2009 12:41:07 -0700 Subject: acerhdf: additional BIOS versions Added BIOS versions: Acer: AOA110-v0.3307, AOA150-v0.3301, AOA150-v0.3307 Packard Bell: AOA150-v0.3105 Signed-off-by: Peter Feuerer Cc: Andreas Mohr Cc: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/platform/x86/acerhdf.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index 5aef16f33841..0a8f735f6c4a 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -139,13 +139,16 @@ static const struct bios_settings_t bios_tbl[] = { {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, + {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} }, {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, /* AOA150 */ {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} }, + {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, + {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, @@ -154,6 +157,7 @@ static const struct bios_settings_t bios_tbl[] = { {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, + {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, /* pewpew-terminator */ {"", "", "", 0, 0, {0, 0} } }; -- cgit v1.2.3-59-g8ed1b From 9ac6185669d0d277c4082fa92ba8eb2e55534cbf Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 31 Aug 2009 22:32:10 +0000 Subject: ACPI: simplify deferred execution path We had two functions, acpi_os_execute_deferred() and acpi_os_execute_hp_deferred() that differed only in that the latter did acpi_os_wait_events_complete(NULL) before executing the deferred function. This patch consolidates those two functions and uses a flag in the struct acpi_os_dpc to determine whether to do the wait. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/osl.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c5b4f1ed9b71..d753206f0734 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -58,6 +58,7 @@ struct acpi_os_dpc { acpi_osd_exec_callback function; void *context; struct work_struct work; + int wait; }; #ifdef CONFIG_ACPI_CUSTOM_DSDT @@ -703,21 +704,8 @@ static void acpi_os_execute_deferred(struct work_struct *work) return; } - dpc->function(dpc->context); - kfree(dpc); - - return; -} - -static void acpi_os_execute_hp_deferred(struct work_struct *work) -{ - struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); - if (!dpc) { - printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); - return; - } - - acpi_os_wait_events_complete(NULL); + if (dpc->wait) + acpi_os_wait_events_complete(NULL); dpc->function(dpc->context); kfree(dpc); @@ -746,7 +734,6 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, acpi_status status = AE_OK; struct acpi_os_dpc *dpc; struct workqueue_struct *queue; - work_func_t func; int ret; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", @@ -779,8 +766,8 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, */ queue = hp ? kacpi_hotplug_wq : (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq); - func = hp ? acpi_os_execute_hp_deferred : acpi_os_execute_deferred; - INIT_WORK(&dpc->work, func); + dpc->wait = hp ? 1 : 0; + INIT_WORK(&dpc->work, acpi_os_execute_deferred); ret = queue_work(queue, &dpc->work); if (!ret) { -- cgit v1.2.3-59-g8ed1b From 59fc9e5e21baf2bf5c87d8006e006007c3a708c2 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 31 Aug 2009 22:32:15 +0000 Subject: ACPI: remove null pointer checks in deferred execution path Better to oops and learn about a bug than to silently cover it up. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/osl.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index d753206f0734..56071b67bed5 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -699,18 +699,12 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ static void acpi_os_execute_deferred(struct work_struct *work) { struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); - if (!dpc) { - printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); - return; - } if (dpc->wait) acpi_os_wait_events_complete(NULL); dpc->function(dpc->context); kfree(dpc); - - return; } /******************************************************************************* @@ -739,9 +733,6 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); - if (!function) - return AE_BAD_PARAMETER; - /* * Allocate/initialize DPC structure. Note that this memory will be * freed by the callee. The kernel handles the work_struct list in a -- cgit v1.2.3-59-g8ed1b From 53de5356be3ac62c22ae1da266943059b169d9b1 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 31 Aug 2009 22:32:20 +0000 Subject: ACPI: don't pass handle for fixed hardware notifications Fixed hardware devices have no handles, so just pass an explicit NULL rather than something that looks like it might be meaningful. acpi_device_notify() doesn't need the handle anyway; the only reason it takes it as an argument is because the acpi_notify_handler typedef requires it. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7b90900b2118..408ebde18986 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -370,7 +370,8 @@ static acpi_status acpi_device_notify_fixed(void *data) { struct acpi_device *device = data; - acpi_device_notify(device->handle, ACPI_FIXED_HARDWARE_EVENT, device); + /* Fixed hardware devices have no handles */ + acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device); return AE_OK; } -- cgit v1.2.3-59-g8ed1b