GIT f3a2c3ee458bd614231e548c13acb0cf33a68631 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git#test Signed-off-by: Andrew Morton --- Documentation/acpi-hotkey.txt | 38 Documentation/kernel-parameters.txt | 5 Documentation/video-output.txt | 34 arch/i386/kernel/acpi/boot.c | 6 arch/ia64/kernel/acpi.c | 3 arch/ia64/sn/kernel/io_acpi_init.c | 3 drivers/acpi/Kconfig | 18 drivers/acpi/Makefile | 6 drivers/acpi/battery.c | 4 drivers/acpi/bay.c | 490 +++++++++ drivers/acpi/bus.c | 5 drivers/acpi/container.c | 6 drivers/acpi/fan.c | 8 drivers/acpi/hotkey.c | 1042 -------------------- drivers/acpi/motherboard.c | 19 drivers/acpi/numa.c | 20 drivers/acpi/pci_root.c | 25 drivers/acpi/processor_core.c | 8 drivers/acpi/scan.c | 1296 ++++++++++++-------------- drivers/acpi/tables.c | 134 +- drivers/acpi/thermal.c | 4 drivers/acpi/video.c | 166 ++- drivers/video/output.c | 129 ++ include/acpi/acpi_bus.h | 22 include/acpi/acpi_drivers.h | 15 include/linux/acpi.h | 7 include/linux/video_output.h | 42 27 files changed, 1640 insertions(+), 1915 deletions(-) diff -puN Documentation/acpi-hotkey.txt~git-acpi /dev/null --- a/Documentation/acpi-hotkey.txt +++ /dev/null @@ -1,38 +0,0 @@ -driver/acpi/hotkey.c implement: -1. /proc/acpi/hotkey/event_config -(event based hotkey or event config interface): -a. add a event based hotkey(event) : -echo "0:bus::action:method:num:num" > event_config - -b. delete a event based hotkey(event): -echo "1:::::num:num" > event_config - -c. modify a event based hotkey(event): -echo "2:bus::action:method:num:num" > event_config - -2. /proc/acpi/hotkey/poll_config -(polling based hotkey or event config interface): -a.add a polling based hotkey(event) : -echo "0:bus:method:action:method:num" > poll_config -this adding command will create a proc file -/proc/acpi/hotkey/method, which is used to get -result of polling. - -b.delete a polling based hotkey(event): -echo "1:::::num" > event_config - -c.modify a polling based hotkey(event): -echo "2:bus:method:action:method:num" > poll_config - -3./proc/acpi/hotkey/action -(interface to call aml method associated with a -specific hotkey(event)) -echo "event_num:event_type:event_argument" > - /proc/acpi/hotkey/action. -The result of the execution of this aml method is -attached to /proc/acpi/hotkey/poll_method, which is dynamically -created. Please use command "cat /proc/acpi/hotkey/polling_method" -to retrieve it. - -Note: Use cmdline "acpi_generic_hotkey" to over-ride -platform-specific with generic driver. diff -puN Documentation/kernel-parameters.txt~git-acpi Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt~git-acpi +++ a/Documentation/kernel-parameters.txt @@ -159,6 +159,11 @@ and is between 256 and 4096 characters. acpi_osi= [HW,ACPI] empty param disables _OSI + acpi_parse_multi_table= + [HW,ACPI] When broken BIOS provides duplicate tables, + parse up to the nth one instead of choosing the 0th one. + Format: + acpi_serialize [HW,ACPI] force serialization of AML methods acpi_skip_timer_override [HW,ACPI] diff -puN /dev/null Documentation/video-output.txt --- /dev/null +++ a/Documentation/video-output.txt @@ -0,0 +1,34 @@ + + Video Output Switcher Control + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 2006 luming.yu@intel.com + +The output sysfs class driver provides an abstract video output layer that +can be used to hook platform specific methods to enable/disable video output +device through common sysfs interface. For example, on my IBM ThinkPad T42 +laptop, The ACPI video driver registered its output devices and read/write +method for 'state' with output sysfs class. The user interface under sysfs is: + +linux:/sys/class/video_output # tree . +. +|-- CRT0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +|-- DVI0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +|-- LCD0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +`-- TV0 + |-- device -> ../../../devices/pci0000:00/0000:00:01.0 + |-- state + |-- subsystem -> ../../../class/video_output + `-- uevent + diff -puN arch/i386/kernel/acpi/boot.c~git-acpi arch/i386/kernel/acpi/boot.c --- a/arch/i386/kernel/acpi/boot.c~git-acpi +++ a/arch/i386/kernel/acpi/boot.c @@ -906,10 +906,10 @@ static inline int acpi_parse_madt_ioapic static void __init acpi_process_madt(void) { #ifdef CONFIG_X86_LOCAL_APIC - int count, error; + int error; - count = acpi_table_parse(ACPI_APIC, acpi_parse_madt); - if (count >= 1) { + error = acpi_table_parse(ACPI_APIC, acpi_parse_madt); + if (!error) { /* * Parse MADT LAPIC entries diff -puN arch/ia64/kernel/acpi.c~git-acpi arch/ia64/kernel/acpi.c --- a/arch/ia64/kernel/acpi.c~git-acpi +++ a/arch/ia64/kernel/acpi.c @@ -590,6 +590,9 @@ void __init acpi_numa_arch_fixup(void) */ int acpi_register_gsi(u32 gsi, int triggering, int polarity) { + if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM) + return gsi; + if (has_8259 && gsi < 16) return isa_irq_to_vector(gsi); diff -puN arch/ia64/sn/kernel/io_acpi_init.c~git-acpi arch/ia64/sn/kernel/io_acpi_init.c --- a/arch/ia64/sn/kernel/io_acpi_init.c~git-acpi +++ a/arch/ia64/sn/kernel/io_acpi_init.c @@ -223,6 +223,9 @@ sn_io_acpi_init(void) u64 result; s64 status; + /* SN Altix does not follow the IOSAPIC IRQ routing model */ + acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM; + acpi_bus_register_driver(&acpi_sn_hubdev_driver); status = sal_ioif_init(&result); if (status || result) diff -puN drivers/acpi/Kconfig~git-acpi drivers/acpi/Kconfig --- a/drivers/acpi/Kconfig~git-acpi +++ a/drivers/acpi/Kconfig @@ -107,7 +107,7 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" - depends on X86 + depends on X86 && BACKLIGHT_CLASS_DEVICE help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in @@ -117,15 +117,6 @@ config ACPI_VIDEO Note that this is an ref. implementation only. It may or may not work for your integrated video device. -config ACPI_HOTKEY - tristate "Generic Hotkey (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on X86 - default n - help - Experimental consolidated hotkey driver. - If you are unsure, say N. - config ACPI_FAN tristate "Fan" default y @@ -139,6 +130,13 @@ config ACPI_DOCK help This driver adds support for ACPI controlled docking stations +config ACPI_BAY + tristate "Removable Drive Bay" + depends on EXPERIMENTAL + help + This driver adds support for ACPI controlled removable drive + bays such as the IBM ultrabay or the Dell Module Bay. + config ACPI_PROCESSOR tristate "Processor" default y diff -puN drivers/acpi/Makefile~git-acpi drivers/acpi/Makefile --- a/drivers/acpi/Makefile~git-acpi +++ a/drivers/acpi/Makefile @@ -37,14 +37,15 @@ endif obj-y += sleep/ obj-y += bus.o glue.o +obj-y += scan.o motherboard.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_DOCK) += dock.o -obj-$(CONFIG_ACPI_VIDEO) += video.o -obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o +obj-$(CONFIG_ACPI_BAY) += bay.o +obj-$(CONFIG_ACPI_VIDEO) += video.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_POWER) += power.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o @@ -56,7 +57,6 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o -obj-y += scan.o motherboard.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-y += cm_sbs.o obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o diff -puN drivers/acpi/battery.c~git-acpi drivers/acpi/battery.c --- a/drivers/acpi/battery.c~git-acpi +++ a/drivers/acpi/battery.c @@ -64,7 +64,7 @@ extern void *acpi_unlock_battery_dir(str static int acpi_battery_add(struct acpi_device *device); static int acpi_battery_remove(struct acpi_device *device, int type); -static int acpi_battery_resume(struct acpi_device *device, int status); +static int acpi_battery_resume(struct acpi_device *device); static struct acpi_driver acpi_battery_driver = { .name = ACPI_BATTERY_DRIVER_NAME, @@ -753,7 +753,7 @@ static int acpi_battery_remove(struct ac } /* this is needed to learn about changes made in suspended state */ -static int acpi_battery_resume(struct acpi_device *device, int state) +static int acpi_battery_resume(struct acpi_device *device) { struct acpi_battery *battery; diff -puN /dev/null drivers/acpi/bay.c --- /dev/null +++ a/drivers/acpi/bay.c @@ -0,0 +1,490 @@ +/* + * bay.c - ACPI removable drive bay driver + * + * Copyright (C) 2006 Kristen Carlson Accardi + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + +#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver" + +ACPI_MODULE_NAME("bay") +MODULE_AUTHOR("Kristen Carlson Accardi"); +MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME); +MODULE_LICENSE("GPL"); +#define ACPI_BAY_CLASS "bay" +#define ACPI_BAY_COMPONENT 0x10000000 +#define _COMPONENT ACPI_BAY_COMPONENT +#define bay_dprintk(h,s) {\ + char prefix[80] = {'\0'};\ + struct acpi_buffer buffer = {sizeof(prefix), prefix};\ + acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ + printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } +static void bay_notify(acpi_handle handle, u32 event, void *data); +static int acpi_bay_add(struct acpi_device *device); +static int acpi_bay_remove(struct acpi_device *device, int type); + +static struct acpi_driver acpi_bay_driver = { + .name = ACPI_BAY_DRIVER_NAME, + .class = ACPI_BAY_CLASS, + .ids = ACPI_BAY_HID, + .ops = { + .add = acpi_bay_add, + .remove = acpi_bay_remove, + }, +}; + +struct bay { + acpi_handle handle; + char *name; + struct list_head list; + struct platform_device *pdev; +}; + +static LIST_HEAD(drive_bays); + + +/***************************************************************************** + * Drive Bay functions * + *****************************************************************************/ +/** + * is_ejectable - see if a device is ejectable + * @handle: acpi handle of the device + * + * If an acpi object has a _EJ0 method, then it is ejectable + */ +static int is_ejectable(acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) + return 0; + return 1; +} + +/** + * bay_present - see if the bay device is present + * @bay: the drive bay + * + * execute the _STA method. + */ +static int bay_present(struct bay *bay) +{ + unsigned long sta; + acpi_status status; + + if (bay) { + status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta) + return 1; + } + return 0; +} + +/** + * eject_device - respond to an eject request + * @handle - the device to eject + * + * Call this devices _EJ0 method. + */ +static void eject_device(acpi_handle handle) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + + bay_dprintk(handle, "Ejecting device"); + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", + &arg_list, NULL))) + pr_debug("Failed to evaluate _EJ0!\n"); +} + +/* + * show_present - read method for "present" file in sysfs + */ +static ssize_t show_present(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bay *bay = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay)); + +} +DEVICE_ATTR(present, S_IRUGO, show_present, NULL); + +/* + * write_eject - write method for "eject" file in sysfs + */ +static ssize_t write_eject(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bay *bay = dev_get_drvdata(dev); + + if (!count) + return -EINVAL; + + eject_device(bay->handle); + return count; +} +DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject); + +/** + * is_ata - see if a device is an ata device + * @handle: acpi handle of the device + * + * If an acpi object has one of 4 ATA ACPI methods defined, + * then it is an ATA device + */ +static int is_ata(acpi_handle handle) +{ + acpi_handle tmp; + + if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + return 1; + + return 0; +} + +/** + * parent_is_ata(acpi_handle handle) + * + */ +static int parent_is_ata(acpi_handle handle) +{ + acpi_handle phandle; + + if (acpi_get_parent(handle, &phandle)) + return 0; + + return is_ata(phandle); +} + +/** + * is_ejectable_bay - see if a device is an ejectable drive bay + * @handle: acpi handle of the device + * + * If an acpi object is ejectable and has one of the ACPI ATA + * methods defined, then we can safely call it an ejectable + * drive bay + */ +static int is_ejectable_bay(acpi_handle handle) +{ + if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle)) + return 1; + return 0; +} + +/** + * eject_removable_drive - try to eject this drive + * @dev : the device structure of the drive + * + * If a device is a removable drive that requires an _EJ0 method + * to be executed in order to safely remove from the system, do + * it. ATM - always returns success + */ +int eject_removable_drive(struct device *dev) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(dev); + + if (handle) { + bay_dprintk(handle, "Got device handle"); + if (is_ejectable_bay(handle)) + eject_device(handle); + } else { + printk("No acpi handle for device\n"); + } + + /* should I return an error code? */ + return 0; +} +EXPORT_SYMBOL_GPL(eject_removable_drive); + +static int acpi_bay_add(struct acpi_device *device) +{ + bay_dprintk(device->handle, "adding bay device"); + strcpy(acpi_device_name(device), "Dockable Bay"); + strcpy(acpi_device_class(device), "bay"); + return 0; +} + +static int acpi_bay_add_fs(struct bay *bay) +{ + int ret; + struct device *dev = &bay->pdev->dev; + + ret = device_create_file(dev, &dev_attr_present); + if (ret) + goto add_fs_err; + ret = device_create_file(dev, &dev_attr_eject); + if (ret) { + device_remove_file(dev, &dev_attr_present); + goto add_fs_err; + } + return 0; + + add_fs_err: + bay_dprintk(bay->handle, "Error adding sysfs files\n"); + return ret; +} + +static void acpi_bay_remove_fs(struct bay *bay) +{ + struct device *dev = &bay->pdev->dev; + + /* cleanup sysfs */ + device_remove_file(dev, &dev_attr_present); + device_remove_file(dev, &dev_attr_eject); +} + +static int bay_is_dock_device(acpi_handle handle) +{ + acpi_handle parent; + + acpi_get_parent(handle, &parent); + + /* if the device or it's parent is dependent on the + * dock, then we are a dock device + */ + return (is_dock_device(handle) || is_dock_device(parent)); +} + +static int bay_add(acpi_handle handle, int id) +{ + acpi_status status; + struct bay *new_bay; + struct platform_device *pdev; + struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer); + + bay_dprintk(handle, "Adding notify handler"); + + /* + * Initialize bay device structure + */ + new_bay = kzalloc(GFP_ATOMIC, sizeof(*new_bay)); + INIT_LIST_HEAD(&new_bay->list); + new_bay->handle = handle; + new_bay->name = (char *)nbuffer.pointer; + + /* initialize platform device stuff */ + pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); + if (pdev == NULL) { + printk(KERN_ERR PREFIX "Error registering bay device\n"); + goto bay_add_err; + } + new_bay->pdev = pdev; + platform_set_drvdata(pdev, new_bay); + + if (acpi_bay_add_fs(new_bay)) { + platform_device_unregister(new_bay->pdev); + goto bay_add_err; + } + + /* register for events on this device */ + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + bay_notify, new_bay); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Error installing bay notify handler\n"); + } + + /* if we are on a dock station, we should register for dock + * notifications. + */ + if (bay_is_dock_device(handle)) { + bay_dprintk(handle, "Is dependent on dock\n"); + register_hotplug_dock_device(handle, bay_notify, new_bay); + } + list_add(&new_bay->list, &drive_bays); + printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name); + return 0; + +bay_add_err: + kfree(new_bay->name); + kfree(new_bay); + return -ENODEV; +} + +static int acpi_bay_remove(struct acpi_device *device, int type) +{ + /*** FIXME: do something here */ + return 0; +} + +/** + * bay_create_acpi_device - add new devices to acpi + * @handle - handle of the device to add + * + * This function will create a new acpi_device for the given + * handle if one does not exist already. This should cause + * acpi to scan for drivers for the given devices, and call + * matching driver's add routine. + * + * Returns a pointer to the acpi_device corresponding to the handle. + */ +static struct acpi_device * bay_create_acpi_device(acpi_handle handle) +{ + struct acpi_device *device = NULL; + struct acpi_device *parent_device; + acpi_handle parent; + int ret; + + bay_dprintk(handle, "Trying to get device"); + if (acpi_bus_get_device(handle, &device)) { + /* + * no device created for this object, + * so we should create one. + */ + bay_dprintk(handle, "No device for handle"); + acpi_get_parent(handle, &parent); + if (acpi_bus_get_device(parent, &parent_device)) + parent_device = NULL; + + ret = acpi_bus_add(&device, parent_device, handle, + ACPI_BUS_TYPE_DEVICE); + if (ret) { + pr_debug("error adding bus, %x\n", + -ret); + return NULL; + } + } + return device; +} + +/** + * bay_notify - act upon an acpi bay notification + * @handle: the bay handle + * @event: the acpi event + * @data: our driver data struct + * + */ +static void bay_notify(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *dev; + + bay_dprintk(handle, "Bay event"); + + switch(event) { + case ACPI_NOTIFY_BUS_CHECK: + printk("Bus Check\n"); + case ACPI_NOTIFY_DEVICE_CHECK: + printk("Device Check\n"); + dev = bay_create_acpi_device(handle); + if (dev) + acpi_bus_generate_event(dev, event, 0); + else + printk("No device for generating event\n"); + /* wouldn't it be a good idea to just rescan SATA + * right here? + */ + break; + case ACPI_NOTIFY_EJECT_REQUEST: + printk("Eject request\n"); + dev = bay_create_acpi_device(handle); + if (dev) + acpi_bus_generate_event(dev, event, 0); + else + printk("No device for generating eventn"); + + /* wouldn't it be a good idea to just call the + * eject_device here if we were a SATA device? + */ + break; + default: + printk("unknown event %d\n", event); + } +} + +static acpi_status +find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + + /* + * there could be more than one ejectable bay. + * so, just return AE_OK always so that every object + * will be checked. + */ + if (is_ejectable_bay(handle)) { + bay_dprintk(handle, "found ejectable bay"); + if (!bay_add(handle, *count)) + (*count)++; + } + return AE_OK; +} + +static int __init bay_init(void) +{ + int bays = 0; + + INIT_LIST_HEAD(&drive_bays); + + /* look for dockable drive bays */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_bay, &bays, NULL); + + if (bays) + if ((acpi_bus_register_driver(&acpi_bay_driver) < 0)) + printk(KERN_ERR "Unable to register bay driver\n"); + + if (!bays) + return -ENODEV; + + return 0; +} + +static void __exit bay_exit(void) +{ + struct bay *bay, *tmp; + + list_for_each_entry_safe(bay, tmp, &drive_bays, list) { + if (is_dock_device(bay->handle)) + unregister_hotplug_dock_device(bay->handle); + acpi_bay_remove_fs(bay); + acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY, + bay_notify); + platform_device_unregister(bay->pdev); + kfree(bay->name); + kfree(bay); + } + + acpi_bus_unregister_driver(&acpi_bay_driver); +} + +postcore_initcall(bay_init); +module_exit(bay_exit); + diff -puN drivers/acpi/bus.c~git-acpi drivers/acpi/bus.c --- a/drivers/acpi/bus.c~git-acpi +++ a/drivers/acpi/bus.c @@ -195,7 +195,7 @@ int acpi_bus_set_power(acpi_handle handl if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - device->kobj.name)); + device->dev.kobj.name)); return -ENODEV; } /* @@ -561,6 +561,9 @@ static int __init acpi_bus_init_irq(void case ACPI_IRQ_MODEL_IOSAPIC: message = "IOSAPIC"; break; + case ACPI_IRQ_MODEL_PLATFORM: + message = "platform specific model"; + break; default: printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n"); return -ENODEV; diff -puN drivers/acpi/container.c~git-acpi drivers/acpi/container.c --- a/drivers/acpi/container.c~git-acpi +++ a/drivers/acpi/container.c @@ -167,7 +167,7 @@ static void container_notify_cb(acpi_han if (ACPI_FAILURE(status) || !device) { result = container_device_add(&device, handle); if (!result) - kobject_uevent(&device->kobj, + kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); else printk("Failed to add container\n"); @@ -175,13 +175,13 @@ static void container_notify_cb(acpi_han } else { if (ACPI_SUCCESS(status)) { /* device exist and this is a remove request */ - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); } } break; case ACPI_NOTIFY_EJECT_REQUEST: if (!acpi_bus_get_device(handle, &device) && device) { - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); } break; default: diff -puN drivers/acpi/fan.c~git-acpi drivers/acpi/fan.c --- a/drivers/acpi/fan.c~git-acpi +++ a/drivers/acpi/fan.c @@ -48,8 +48,8 @@ MODULE_LICENSE("GPL"); static int acpi_fan_add(struct acpi_device *device); static int acpi_fan_remove(struct acpi_device *device, int type); -static int acpi_fan_suspend(struct acpi_device *device, int state); -static int acpi_fan_resume(struct acpi_device *device, int state); +static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state); +static int acpi_fan_resume(struct acpi_device *device); static struct acpi_driver acpi_fan_driver = { .name = ACPI_FAN_DRIVER_NAME, @@ -237,7 +237,7 @@ static int acpi_fan_remove(struct acpi_d return 0; } -static int acpi_fan_suspend(struct acpi_device *device, int state) +static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state) { if (!device) return -EINVAL; @@ -247,7 +247,7 @@ static int acpi_fan_suspend(struct acpi_ return AE_OK; } -static int acpi_fan_resume(struct acpi_device *device, int state) +static int acpi_fan_resume(struct acpi_device *device) { int result = 0; int power_state = 0; diff -puN drivers/acpi/hotkey.c~git-acpi /dev/null --- a/drivers/acpi/hotkey.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * hotkey.c - ACPI Hotkey Driver ($Revision: 0.2 $) - * - * Copyright (C) 2004 Luming Yu - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * 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 HOTKEY_ACPI_VERSION "0.1" - -#define HOTKEY_PROC "hotkey" -#define HOTKEY_EV_CONFIG "event_config" -#define HOTKEY_PL_CONFIG "poll_config" -#define HOTKEY_ACTION "action" -#define HOTKEY_INFO "info" - -#define ACPI_HOTK_NAME "Generic Hotkey Driver" -#define ACPI_HOTK_CLASS "Hotkey" -#define ACPI_HOTK_DEVICE_NAME "Hotkey" -#define ACPI_HOTK_HID "Unknown?" -#define ACPI_HOTKEY_COMPONENT 0x20000000 - -#define ACPI_HOTKEY_EVENT 0x1 -#define ACPI_HOTKEY_POLLING 0x2 -#define ACPI_UNDEFINED_EVENT 0xf - -#define RESULT_STR_LEN 80 - -#define ACTION_METHOD 0 -#define POLL_METHOD 1 - -#define IS_EVENT(e) ((e) <= 10000 && (e) >0) -#define IS_POLL(e) ((e) > 10000) -#define IS_OTHERS(e) ((e)<=0 || (e)>=20000) -#define _COMPONENT ACPI_HOTKEY_COMPONENT -ACPI_MODULE_NAME("acpi_hotkey") - - MODULE_AUTHOR("luming.yu@intel.com"); -MODULE_DESCRIPTION(ACPI_HOTK_NAME); -MODULE_LICENSE("GPL"); - -/* standardized internal hotkey number/event */ -enum { - /* Video Extension event */ - HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80, - HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE, - HK_EVENT_CYCLE_DISPLAY_OUTPUT, - HK_EVENT_NEXT_DISPLAY_OUTPUT, - HK_EVENT_PREVIOUS_DISPLAY_OUTPUT, - HK_EVENT_CYCLE_BRIGHTNESS, - HK_EVENT_INCREASE_BRIGHTNESS, - HK_EVENT_DECREASE_BRIGHTNESS, - HK_EVENT_ZERO_BRIGHTNESS, - HK_EVENT_DISPLAY_DEVICE_OFF, - - /* Snd Card event */ - HK_EVENT_VOLUME_MUTE, - HK_EVENT_VOLUME_INCLREASE, - HK_EVENT_VOLUME_DECREASE, - - /* running state control */ - HK_EVENT_ENTERRING_S3, - HK_EVENT_ENTERRING_S4, - HK_EVENT_ENTERRING_S5, -}; - -enum conf_entry_enum { - bus_handle = 0, - bus_method = 1, - action_handle = 2, - method = 3, - LAST_CONF_ENTRY -}; - -/* procdir we use */ -static struct proc_dir_entry *hotkey_proc_dir; -static struct proc_dir_entry *hotkey_config; -static struct proc_dir_entry *hotkey_poll_config; -static struct proc_dir_entry *hotkey_action; -static struct proc_dir_entry *hotkey_info; - -/* linkage for all type of hotkey */ -struct acpi_hotkey_link { - struct list_head entries; - int hotkey_type; /* event or polling based hotkey */ - int hotkey_standard_num; /* standardized hotkey(event) number */ -}; - -/* event based hotkey */ -struct acpi_event_hotkey { - struct acpi_hotkey_link hotkey_link; - int flag; - acpi_handle bus_handle; /* bus to install notify handler */ - int external_hotkey_num; /* external hotkey/event number */ - acpi_handle action_handle; /* acpi handle attached aml action method */ - char *action_method; /* action method */ -}; - -/* - * There are two ways to poll status - * 1. directy call read_xxx method, without any arguments passed in - * 2. call write_xxx method, with arguments passed in, you need - * the result is saved in acpi_polling_hotkey.poll_result. - * anthoer read command through polling interface. - * - */ - -/* polling based hotkey */ -struct acpi_polling_hotkey { - struct acpi_hotkey_link hotkey_link; - int flag; - acpi_handle poll_handle; /* acpi handle attached polling method */ - char *poll_method; /* poll method */ - acpi_handle action_handle; /* acpi handle attached action method */ - char *action_method; /* action method */ - union acpi_object *poll_result; /* polling_result */ - struct proc_dir_entry *proc; -}; - -/* hotkey object union */ -union acpi_hotkey { - struct list_head entries; - struct acpi_hotkey_link link; - struct acpi_event_hotkey event_hotkey; - struct acpi_polling_hotkey poll_hotkey; -}; - -/* hotkey object list */ -struct acpi_hotkey_list { - struct list_head *entries; - int count; -}; - -static int auto_hotkey_add(struct acpi_device *device); -static int auto_hotkey_remove(struct acpi_device *device, int type); - -static struct acpi_driver hotkey_driver = { - .name = ACPI_HOTK_NAME, - .class = ACPI_HOTK_CLASS, - .ids = ACPI_HOTK_HID, - .ops = { - .add = auto_hotkey_add, - .remove = auto_hotkey_remove, - }, -}; - -static void free_hotkey_device(union acpi_hotkey *key); -static void free_hotkey_buffer(union acpi_hotkey *key); -static void free_poll_hotkey_buffer(union acpi_hotkey *key); -static int hotkey_open_config(struct inode *inode, struct file *file); -static int hotkey_poll_open_config(struct inode *inode, struct file *file); -static ssize_t hotkey_write_config(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); -static int hotkey_info_open_fs(struct inode *inode, struct file *file); -static int hotkey_action_open_fs(struct inode *inode, struct file *file); -static ssize_t hotkey_execute_aml_method(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); -static int hotkey_config_seq_show(struct seq_file *seq, void *offset); -static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset); -static int hotkey_polling_open_fs(struct inode *inode, struct file *file); -static union acpi_hotkey *get_hotkey_by_event(struct - acpi_hotkey_list - *hotkey_list, int event); - -/* event based config */ -static const struct file_operations hotkey_config_fops = { - .open = hotkey_open_config, - .read = seq_read, - .write = hotkey_write_config, - .llseek = seq_lseek, - .release = single_release, -}; - -/* polling based config */ -static const struct file_operations hotkey_poll_config_fops = { - .open = hotkey_poll_open_config, - .read = seq_read, - .write = hotkey_write_config, - .llseek = seq_lseek, - .release = single_release, -}; - -/* hotkey driver info */ -static const struct file_operations hotkey_info_fops = { - .open = hotkey_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* action */ -static const struct file_operations hotkey_action_fops = { - .open = hotkey_action_open_fs, - .read = seq_read, - .write = hotkey_execute_aml_method, - .llseek = seq_lseek, - .release = single_release, -}; - -/* polling results */ -static const struct file_operations hotkey_polling_fops = { - .open = hotkey_polling_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */ -struct list_head hotkey_entries; /* head of the list of hotkey_list */ - -static int hotkey_info_seq_show(struct seq_file *seq, void *offset) -{ - - seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION); - - return 0; -} - -static int hotkey_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_info_seq_show, PDE(inode)->data); -} - -static char *format_result(union acpi_object *object) -{ - char *buf; - - buf = kzalloc(RESULT_STR_LEN, GFP_KERNEL); - if (!buf) - return NULL; - /* Now, just support integer type */ - if (object->type == ACPI_TYPE_INTEGER) - sprintf(buf, "%d\n", (u32) object->integer.value); - return buf; -} - -static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_polling_hotkey *poll_hotkey = seq->private; - char *buf; - - - if (poll_hotkey->poll_result) { - buf = format_result(poll_hotkey->poll_result); - if (buf) - seq_printf(seq, "%s", buf); - kfree(buf); - } - return 0; -} - -static int hotkey_polling_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_polling_seq_show, PDE(inode)->data); -} - -static int hotkey_action_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_info_seq_show, PDE(inode)->data); -} - -/* Mapping external hotkey number to standardized hotkey event num */ -static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list) -{ - struct list_head *entries; - int val = -1; - - - list_for_each(entries, list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT - && key->event_hotkey.external_hotkey_num == event) { - val = key->link.hotkey_standard_num; - break; - } - } - - return val; -} - -static void -acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data) -{ - struct acpi_device *device = NULL; - u32 internal_event; - - - if (acpi_bus_get_device(handle, &device)) - return; - - internal_event = hotkey_get_internal_event(event, &global_hotkey_list); - acpi_bus_generate_event(device, internal_event, 0); - - return; -} - -/* Need to invent automatically hotkey add method */ -static int auto_hotkey_add(struct acpi_device *device) -{ - /* Implement me */ - return 0; -} - -/* Need to invent automatically hotkey remove method */ -static int auto_hotkey_remove(struct acpi_device *device, int type) -{ - /* Implement me */ - return 0; -} - -/* Create a proc file for each polling method */ -static int create_polling_proc(union acpi_hotkey *device) -{ - struct proc_dir_entry *proc; - char proc_name[80]; - mode_t mode; - - mode = S_IFREG | S_IRUGO | S_IWUGO; - - sprintf(proc_name, "%d", device->link.hotkey_standard_num); - /* - strcat(proc_name, device->poll_hotkey.poll_method); - */ - proc = create_proc_entry(proc_name, mode, hotkey_proc_dir); - - if (!proc) { - return -ENODEV; - } else { - proc->proc_fops = &hotkey_polling_fops; - proc->owner = THIS_MODULE; - proc->data = device; - proc->uid = 0; - proc->gid = 0; - device->poll_hotkey.proc = proc; - } - return 0; -} - -static int hotkey_add(union acpi_hotkey *device) -{ - int status = 0; - struct acpi_device *dev = NULL; - - - if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_bus_get_device(device->event_hotkey.bus_handle, &dev); - status = acpi_install_notify_handler(dev->handle, - ACPI_DEVICE_NOTIFY, - acpi_hotkey_notify_handler, - dev); - } else /* Add polling hotkey */ - create_polling_proc(device); - - global_hotkey_list.count++; - - list_add_tail(&device->link.entries, global_hotkey_list.entries); - - return status; -} - -static int hotkey_remove(union acpi_hotkey *device) -{ - struct list_head *entries, *next; - - - list_for_each_safe(entries, next, global_hotkey_list.entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_standard_num == - device->link.hotkey_standard_num) { - list_del(&key->link.entries); - free_hotkey_device(key); - global_hotkey_list.count--; - break; - } - } - kfree(device); - return 0; -} - -static int hotkey_update(union acpi_hotkey *key) -{ - struct list_head *entries; - - - list_for_each(entries, global_hotkey_list.entries) { - union acpi_hotkey *tmp = - container_of(entries, union acpi_hotkey, entries); - if (tmp->link.hotkey_standard_num == - key->link.hotkey_standard_num) { - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - free_hotkey_buffer(tmp); - tmp->event_hotkey.bus_handle = - key->event_hotkey.bus_handle; - tmp->event_hotkey.external_hotkey_num = - key->event_hotkey.external_hotkey_num; - tmp->event_hotkey.action_handle = - key->event_hotkey.action_handle; - tmp->event_hotkey.action_method = - key->event_hotkey.action_method; - kfree(key); - } else { - /* - char proc_name[80]; - - sprintf(proc_name, "%d", tmp->link.hotkey_standard_num); - strcat(proc_name, tmp->poll_hotkey.poll_method); - remove_proc_entry(proc_name,hotkey_proc_dir); - */ - free_poll_hotkey_buffer(tmp); - tmp->poll_hotkey.poll_handle = - key->poll_hotkey.poll_handle; - tmp->poll_hotkey.poll_method = - key->poll_hotkey.poll_method; - tmp->poll_hotkey.action_handle = - key->poll_hotkey.action_handle; - tmp->poll_hotkey.action_method = - key->poll_hotkey.action_method; - tmp->poll_hotkey.poll_result = - key->poll_hotkey.poll_result; - /* - create_polling_proc(tmp); - */ - kfree(key); - } - return 0; - break; - } - } - - return -ENODEV; -} - -static void free_hotkey_device(union acpi_hotkey *key) -{ - struct acpi_device *dev; - - - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_bus_get_device(key->event_hotkey.bus_handle, &dev); - if (dev->handle) - acpi_remove_notify_handler(dev->handle, - ACPI_DEVICE_NOTIFY, - acpi_hotkey_notify_handler); - free_hotkey_buffer(key); - } else { - char proc_name[80]; - - sprintf(proc_name, "%d", key->link.hotkey_standard_num); - /* - strcat(proc_name, key->poll_hotkey.poll_method); - */ - remove_proc_entry(proc_name, hotkey_proc_dir); - free_poll_hotkey_buffer(key); - } - kfree(key); - return; -} - -static void free_hotkey_buffer(union acpi_hotkey *key) -{ - /* key would never be null, action method could be */ - kfree(key->event_hotkey.action_method); -} - -static void free_poll_hotkey_buffer(union acpi_hotkey *key) -{ - /* key would never be null, others could be*/ - kfree(key->poll_hotkey.action_method); - kfree(key->poll_hotkey.poll_method); - kfree(key->poll_hotkey.poll_result); -} -static int -init_hotkey_device(union acpi_hotkey *key, char **config_entry, - int std_num, int external_num) -{ - acpi_handle tmp_handle; - acpi_status status = AE_OK; - - if (std_num < 0 || IS_POLL(std_num) || !key) - goto do_fail; - - if (!config_entry[bus_handle] || !config_entry[action_handle] - || !config_entry[method]) - goto do_fail; - - key->link.hotkey_type = ACPI_HOTKEY_EVENT; - key->link.hotkey_standard_num = std_num; - key->event_hotkey.flag = 0; - key->event_hotkey.action_method = config_entry[method]; - - status = acpi_get_handle(NULL, config_entry[bus_handle], - &(key->event_hotkey.bus_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - key->event_hotkey.external_hotkey_num = external_num; - status = acpi_get_handle(NULL, config_entry[action_handle], - &(key->event_hotkey.action_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->event_hotkey.action_handle, - config_entry[method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - return AE_OK; -do_fail_zero: - key->event_hotkey.action_method = NULL; -do_fail: - return -ENODEV; -} - -static int -init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry, - int std_num) -{ - acpi_status status = AE_OK; - acpi_handle tmp_handle; - - if (std_num < 0 || IS_EVENT(std_num) || !key) - goto do_fail; - if (!config_entry[bus_handle] ||!config_entry[bus_method] || - !config_entry[action_handle] || !config_entry[method]) - goto do_fail; - - key->link.hotkey_type = ACPI_HOTKEY_POLLING; - key->link.hotkey_standard_num = std_num; - key->poll_hotkey.flag = 0; - key->poll_hotkey.poll_method = config_entry[bus_method]; - key->poll_hotkey.action_method = config_entry[method]; - - status = acpi_get_handle(NULL, config_entry[bus_handle], - &(key->poll_hotkey.poll_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->poll_hotkey.poll_handle, - config_entry[bus_method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = - acpi_get_handle(NULL, config_entry[action_handle], - &(key->poll_hotkey.action_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->poll_hotkey.action_handle, - config_entry[method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - key->poll_hotkey.poll_result = - kmalloc(sizeof(union acpi_object), GFP_KERNEL); - if (!key->poll_hotkey.poll_result) - goto do_fail_zero; - return AE_OK; - -do_fail_zero: - key->poll_hotkey.poll_method = NULL; - key->poll_hotkey.action_method = NULL; -do_fail: - return -ENODEV; -} - -static int hotkey_open_config(struct inode *inode, struct file *file) -{ - return (single_open - (file, hotkey_config_seq_show, PDE(inode)->data)); -} - -static int hotkey_poll_open_config(struct inode *inode, struct file *file) -{ - return (single_open - (file, hotkey_poll_config_seq_show, PDE(inode)->data)); -} - -static int hotkey_config_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - struct list_head *entries; - char bus_name[ACPI_PATHNAME_MAX] = { 0 }; - char action_name[ACPI_PATHNAME_MAX] = { 0 }; - struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; - struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; - - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_get_name(key->event_hotkey.bus_handle, - ACPI_NAME_TYPE_MAX, &bus); - acpi_get_name(key->event_hotkey.action_handle, - ACPI_NAME_TYPE_MAX, &act); - seq_printf(seq, "%s:%s:%s:%d:%d\n", bus_name, - action_name, - key->event_hotkey.action_method, - key->link.hotkey_standard_num, - key->event_hotkey.external_hotkey_num); - } - } - seq_puts(seq, "\n"); - return 0; -} - -static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - struct list_head *entries; - char bus_name[ACPI_PATHNAME_MAX] = { 0 }; - char action_name[ACPI_PATHNAME_MAX] = { 0 }; - struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; - struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; - - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_POLLING) { - acpi_get_name(key->poll_hotkey.poll_handle, - ACPI_NAME_TYPE_MAX, &bus); - acpi_get_name(key->poll_hotkey.action_handle, - ACPI_NAME_TYPE_MAX, &act); - seq_printf(seq, "%s:%s:%s:%s:%d\n", bus_name, - key->poll_hotkey.poll_method, - action_name, - key->poll_hotkey.action_method, - key->link.hotkey_standard_num); - } - } - seq_puts(seq, "\n"); - return 0; -} - -static int -get_parms(char *config_record, int *cmd, char **config_entry, - int *internal_event_num, int *external_event_num) -{ -/* the format of *config_record = - * "1:\d+:*" : "cmd:internal_event_num" - * "\d+:\w+:\w+:\w+:\w+:\d+:\d+" : - * "cmd:bus_handle:bus_method:action_handle:method:internal_event_num:external_event_num" - */ - char *tmp, *tmp1, count; - int i; - - sscanf(config_record, "%d", cmd); - if (*cmd == 1) { - if (sscanf(config_record, "%d:%d", cmd, internal_event_num) != - 2) - goto do_fail; - else - return (6); - } - tmp = strchr(config_record, ':'); - if (!tmp) - goto do_fail; - tmp++; - for (i = 0; i < LAST_CONF_ENTRY; i++) { - tmp1 = strchr(tmp, ':'); - if (!tmp1) { - goto do_fail; - } - count = tmp1 - tmp; - config_entry[i] = kzalloc(count + 1, GFP_KERNEL); - if (!config_entry[i]) - goto handle_failure; - strncpy(config_entry[i], tmp, count); - tmp = tmp1 + 1; - } - if (sscanf(tmp, "%d:%d", internal_event_num, external_event_num) <= 0) - goto handle_failure; - if (!IS_OTHERS(*internal_event_num)) { - return 6; - } -handle_failure: - while (i-- > 0) - kfree(config_entry[i]); -do_fail: - return -1; -} - -/* count is length for one input record */ -static ssize_t hotkey_write_config(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - char *config_record = NULL; - char *config_entry[LAST_CONF_ENTRY]; - int cmd, internal_event_num, external_event_num; - int ret = 0; - union acpi_hotkey *key = kzalloc(sizeof(union acpi_hotkey), GFP_KERNEL); - - if (!key) - return -ENOMEM; - - config_record = kzalloc(count + 1, GFP_KERNEL); - if (!config_record) { - kfree(key); - return -ENOMEM; - } - - if (copy_from_user(config_record, buffer, count)) { - kfree(config_record); - kfree(key); - printk(KERN_ERR PREFIX "Invalid data\n"); - return -EINVAL; - } - ret = get_parms(config_record, &cmd, config_entry, - &internal_event_num, &external_event_num); - kfree(config_record); - if (ret != 6) { - printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret); - return -EINVAL; - } - - if (cmd == 1) { - union acpi_hotkey *tmp = NULL; - tmp = get_hotkey_by_event(&global_hotkey_list, - internal_event_num); - if (!tmp) - printk(KERN_ERR PREFIX "Invalid key\n"); - else - memcpy(key, tmp, sizeof(union acpi_hotkey)); - goto cont_cmd; - } - if (IS_EVENT(internal_event_num)) { - if (init_hotkey_device(key, config_entry, - internal_event_num, external_event_num)) - goto init_hotkey_fail; - } else { - if (init_poll_hotkey_device(key, config_entry, - internal_event_num)) - goto init_poll_hotkey_fail; - } -cont_cmd: - switch (cmd) { - case 0: - if (get_hotkey_by_event(&global_hotkey_list, - key->link.hotkey_standard_num)) - goto fail_out; - else - hotkey_add(key); - break; - case 1: - hotkey_remove(key); - break; - case 2: - /* key is kfree()ed if matched*/ - if (hotkey_update(key)) - goto fail_out; - break; - default: - goto fail_out; - break; - } - return count; - -init_poll_hotkey_fail: /* failed init_poll_hotkey_device */ - kfree(config_entry[bus_method]); - config_entry[bus_method] = NULL; -init_hotkey_fail: /* failed init_hotkey_device */ - kfree(config_entry[method]); -fail_out: - kfree(config_entry[bus_handle]); - kfree(config_entry[action_handle]); - /* No double free since elements =NULL for error cases */ - if (IS_EVENT(internal_event_num)) { - if (config_entry[bus_method]) - kfree(config_entry[bus_method]); - free_hotkey_buffer(key); /* frees [method] */ - } else - free_poll_hotkey_buffer(key); /* frees [bus_method]+[method] */ - kfree(key); - printk(KERN_ERR PREFIX "invalid key\n"); - return -EINVAL; -} - -/* - * This function evaluates an ACPI method, given an int as parameter, the - * method is searched within the scope of the handle, can be NULL. The output - * of the method is written is output, which can also be NULL - * - * returns 1 if write is successful, 0 else. - */ -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 */ - acpi_status status; - - params.count = 1; - params.pointer = &in_obj; - in_obj.type = ACPI_TYPE_INTEGER; - in_obj.integer.value = val; - - status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); - - return (status == AE_OK); -} - -static int read_acpi_int(acpi_handle handle, const char *method, - union acpi_object *val) -{ - struct acpi_buffer output; - union acpi_object out_obj; - acpi_status status; - - output.length = sizeof(out_obj); - output.pointer = &out_obj; - - status = acpi_evaluate_object(handle, (char *)method, NULL, &output); - if (val) { - val->integer.value = out_obj.integer.value; - val->type = out_obj.type; - } else - printk(KERN_ERR PREFIX "null val pointer\n"); - return ((status == AE_OK) - && (out_obj.type == ACPI_TYPE_INTEGER)); -} - -static union acpi_hotkey *get_hotkey_by_event(struct - acpi_hotkey_list - *hotkey_list, int event) -{ - struct list_head *entries; - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_standard_num == event) { - return (key); - } - } - return (NULL); -} - -/* - * user call AML method interface: - * Call convention: - * echo "event_num: arg type : value" - * example: echo "1:1:30" > /proc/acpi/action - * Just support 1 integer arg passing to AML method - */ - -static ssize_t hotkey_execute_aml_method(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - char *arg; - int event, method_type, type, value; - union acpi_hotkey *key; - - - arg = kzalloc(count + 1, GFP_KERNEL); - if (!arg) - return -ENOMEM; - - if (copy_from_user(arg, buffer, count)) { - kfree(arg); - printk(KERN_ERR PREFIX "Invalid argument 2\n"); - return -EINVAL; - } - - if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) != - 4) { - kfree(arg); - printk(KERN_ERR PREFIX "Invalid argument 3\n"); - return -EINVAL; - } - kfree(arg); - if (type == ACPI_TYPE_INTEGER) { - key = get_hotkey_by_event(hotkey_list, event); - if (!key) - goto do_fail; - if (IS_EVENT(event)) - write_acpi_int(key->event_hotkey.action_handle, - key->event_hotkey.action_method, value, - NULL); - else if (IS_POLL(event)) { - if (method_type == POLL_METHOD) - read_acpi_int(key->poll_hotkey.poll_handle, - key->poll_hotkey.poll_method, - key->poll_hotkey.poll_result); - else if (method_type == ACTION_METHOD) - write_acpi_int(key->poll_hotkey.action_handle, - key->poll_hotkey.action_method, - value, NULL); - else - goto do_fail; - - } - } else { - printk(KERN_WARNING "Not supported\n"); - return -EINVAL; - } - return count; - do_fail: - return -EINVAL; - -} - -static int __init hotkey_init(void) -{ - int result; - mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; - - - if (acpi_disabled) - return -ENODEV; - - if (acpi_specific_hotkey_enabled) { - printk("Using specific hotkey driver\n"); - return -ENODEV; - } - - hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir); - if (!hotkey_proc_dir) { - return (-ENODEV); - } - hotkey_proc_dir->owner = THIS_MODULE; - - hotkey_config = - create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir); - if (!hotkey_config) { - goto do_fail1; - } else { - hotkey_config->proc_fops = &hotkey_config_fops; - hotkey_config->data = &global_hotkey_list; - hotkey_config->owner = THIS_MODULE; - hotkey_config->uid = 0; - hotkey_config->gid = 0; - } - - hotkey_poll_config = - create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir); - if (!hotkey_poll_config) { - goto do_fail2; - } else { - hotkey_poll_config->proc_fops = &hotkey_poll_config_fops; - hotkey_poll_config->data = &global_hotkey_list; - hotkey_poll_config->owner = THIS_MODULE; - hotkey_poll_config->uid = 0; - hotkey_poll_config->gid = 0; - } - - hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir); - if (!hotkey_action) { - goto do_fail3; - } else { - hotkey_action->proc_fops = &hotkey_action_fops; - hotkey_action->owner = THIS_MODULE; - hotkey_action->uid = 0; - hotkey_action->gid = 0; - } - - hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir); - if (!hotkey_info) { - goto do_fail4; - } else { - hotkey_info->proc_fops = &hotkey_info_fops; - hotkey_info->owner = THIS_MODULE; - hotkey_info->uid = 0; - hotkey_info->gid = 0; - } - - result = acpi_bus_register_driver(&hotkey_driver); - if (result < 0) - goto do_fail5; - global_hotkey_list.count = 0; - global_hotkey_list.entries = &hotkey_entries; - - INIT_LIST_HEAD(&hotkey_entries); - - return (0); - - do_fail5: - remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); - do_fail4: - remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); - do_fail3: - remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); - do_fail2: - remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); - do_fail1: - remove_proc_entry(HOTKEY_PROC, acpi_root_dir); - return (-ENODEV); -} - -static void __exit hotkey_exit(void) -{ - struct list_head *entries, *next; - - - list_for_each_safe(entries, next, global_hotkey_list.entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - - acpi_os_wait_events_complete(NULL); - list_del(&key->link.entries); - global_hotkey_list.count--; - free_hotkey_device(key); - } - acpi_bus_unregister_driver(&hotkey_driver); - remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); - remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); - remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); - remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); - remove_proc_entry(HOTKEY_PROC, acpi_root_dir); - return; -} - -module_init(hotkey_init); -module_exit(hotkey_exit); diff -puN drivers/acpi/motherboard.c~git-acpi drivers/acpi/motherboard.c --- a/drivers/acpi/motherboard.c~git-acpi +++ a/drivers/acpi/motherboard.c @@ -33,8 +33,7 @@ ACPI_MODULE_NAME("acpi_motherboard") /* Dell use PNP0C01 instead of PNP0C02 */ -#define ACPI_MB_HID1 "PNP0C01" -#define ACPI_MB_HID2 "PNP0C02" +#define ACPI_MB_HID "PNP0C01,PNP0C02" /** * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved * Doesn't care about the failure of 'request_region', since other may reserve @@ -110,19 +109,10 @@ static int acpi_motherboard_add(struct a return 0; } -static struct acpi_driver acpi_motherboard_driver1 = { +static struct acpi_driver acpi_motherboard_driver = { .name = "motherboard", .class = "", - .ids = ACPI_MB_HID1, - .ops = { - .add = acpi_motherboard_add, - }, -}; - -static struct acpi_driver acpi_motherboard_driver2 = { - .name = "motherboard", - .class = "", - .ids = ACPI_MB_HID2, + .ids = ACPI_MB_HID, .ops = { .add = acpi_motherboard_add, }, @@ -173,8 +163,7 @@ static void __init acpi_reserve_resource static int __init acpi_motherboard_init(void) { - acpi_bus_register_driver(&acpi_motherboard_driver1); - acpi_bus_register_driver(&acpi_motherboard_driver2); + acpi_bus_register_driver(&acpi_motherboard_driver); /* * Guarantee motherboard IO reservation first * This module must run after scan.c diff -puN drivers/acpi/numa.c~git-acpi drivers/acpi/numa.c --- a/drivers/acpi/numa.c~git-acpi +++ a/drivers/acpi/numa.c @@ -45,10 +45,10 @@ int __cpuinitdata pxm_to_node_map[MAX_PX int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; -extern int __init acpi_table_parse_madt_family(enum acpi_table_id id, +extern int __init acpi_table_parse_entries(enum acpi_table_id id, unsigned long madt_size, int entry_id, - acpi_madt_entry_handler handler, + acpi_table_entry_handler handler, unsigned int max_entries); int __cpuinit pxm_to_node(int pxm) @@ -209,29 +209,29 @@ static int __init acpi_parse_srat(unsign int __init acpi_table_parse_srat(enum acpi_srat_entry_id id, - acpi_madt_entry_handler handler, unsigned int max_entries) + acpi_table_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SRAT, + return acpi_table_parse_entries(ACPI_SRAT, sizeof(struct acpi_table_srat), id, handler, max_entries); } int __init acpi_numa_init(void) { - int result; + int error; /* SRAT: Static Resource Affinity Table */ - result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat); + error = acpi_table_parse(ACPI_SRAT, acpi_parse_srat); - if (result > 0) { - result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY, + if (!error) { + acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY, acpi_parse_processor_affinity, NR_CPUS); - result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific + acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific } /* SLIT: System Locality Information Table */ - result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit); + acpi_table_parse(ACPI_SLIT, acpi_parse_slit); acpi_numa_arch_fixup(); return 0; diff -puN drivers/acpi/pci_root.c~git-acpi drivers/acpi/pci_root.c --- a/drivers/acpi/pci_root.c~git-acpi +++ a/drivers/acpi/pci_root.c @@ -152,6 +152,21 @@ static acpi_status try_get_root_bridge_b return AE_OK; } +static void acpi_pci_bridge_scan(struct acpi_device *device) +{ + int status; + struct acpi_device *child = NULL; + + if (device->flags.bus_address) + if (device->parent && device->parent->ops.bind) { + status = device->parent->ops.bind(device); + if (!status) { + list_for_each_entry(child, &device->children, node) + acpi_pci_bridge_scan(child); + } + } +} + static int acpi_pci_root_add(struct acpi_device *device) { int result = 0; @@ -160,6 +175,7 @@ static int acpi_pci_root_add(struct acpi acpi_status status = AE_OK; unsigned long value = 0; acpi_handle handle = NULL; + struct acpi_device *child; if (!device) @@ -175,9 +191,6 @@ static int acpi_pci_root_add(struct acpi strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); acpi_driver_data(device) = root; - /* - * TBD: Doesn't the bus driver automatically set this? - */ device->ops.bind = acpi_pci_bind; /* @@ -299,6 +312,12 @@ static int acpi_pci_root_add(struct acpi result = acpi_pci_irq_add_prt(device->handle, root->id.segment, root->id.bus); + /* + * Scan and bind all _ADR-Based Devices + */ + list_for_each_entry(child, &device->children, node) + acpi_pci_bridge_scan(child); + end: if (result) { if (!list_empty(&root->node)) diff -puN drivers/acpi/processor_core.c~git-acpi drivers/acpi/processor_core.c --- a/drivers/acpi/processor_core.c~git-acpi +++ a/drivers/acpi/processor_core.c @@ -710,7 +710,7 @@ int acpi_processor_device_add(acpi_handl return -ENODEV; if ((pr->id >= 0) && (pr->id < NR_CPUS)) { - kobject_uevent(&(*device)->kobj, KOBJ_ONLINE); + kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE); } return 0; } @@ -748,13 +748,13 @@ acpi_processor_hotplug_notify(acpi_handl } if (pr->id >= 0 && (pr->id < NR_CPUS)) { - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); break; } result = acpi_processor_start(device); if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) { - kobject_uevent(&device->kobj, KOBJ_ONLINE); + kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); } else { printk(KERN_ERR PREFIX "Device [%s] failed to start\n", acpi_device_bid(device)); @@ -777,7 +777,7 @@ acpi_processor_hotplug_notify(acpi_handl } if ((pr->id < NR_CPUS) && (cpu_present(pr->id))) - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, diff -puN drivers/acpi/scan.c~git-acpi drivers/acpi/scan.c --- a/drivers/acpi/scan.c~git-acpi +++ a/drivers/acpi/scan.c @@ -21,470 +21,408 @@ extern struct acpi_device *acpi_root; #define ACPI_BUS_DEVICE_NAME "System Bus" static LIST_HEAD(acpi_device_list); +static LIST_HEAD(acpi_bus_id_list); DEFINE_SPINLOCK(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); - -static void acpi_device_release(struct kobject *kobj) -{ - struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj); - kfree(dev->pnp.cid_list); - kfree(dev); -} - -struct acpi_device_attribute { - struct attribute attr; - ssize_t(*show) (struct acpi_device *, char *); - ssize_t(*store) (struct acpi_device *, const char *, size_t); +struct acpi_device_bus_id{ + char bus_id[15]; + unsigned int instance_no; + struct list_head node; }; - -typedef void acpi_device_sysfs_files(struct kobject *, - const struct attribute *); - -static void setup_sys_fs_device_files(struct acpi_device *dev, - acpi_device_sysfs_files * func); - -#define create_sysfs_device_files(dev) \ - setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file) -#define remove_sysfs_device_files(dev) \ - setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file) - -#define to_acpi_device(n) container_of(n, struct acpi_device, kobj) -#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr); - -static ssize_t acpi_device_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct acpi_device *device = to_acpi_device(kobj); - struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->show ? attribute->show(device, buf) : -EIO; -} -static ssize_t acpi_device_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, - size_t len) +static int acpi_eject_operation(acpi_handle handle, int lockable) { - struct acpi_device *device = to_acpi_device(kobj); - struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->store ? attribute->store(device, buf, len) : -EIO; -} - -static struct sysfs_ops acpi_device_sysfs_ops = { - .show = acpi_device_attr_show, - .store = acpi_device_attr_store, -}; + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status = AE_OK; -static struct kobj_type ktype_acpi_ns = { - .sysfs_ops = &acpi_device_sysfs_ops, - .release = acpi_device_release, -}; + /* + * TBD: evaluate _PS3? + */ -static int namespace_uevent(struct kset *kset, struct kobject *kobj, - char **envp, int num_envp, char *buffer, - int buffer_size) -{ - struct acpi_device *dev = to_acpi_device(kobj); - int i = 0; - int len = 0; + if (lockable) { + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 0; + acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); + } - if (!dev->driver) - return 0; + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "PHYSDEVDRIVER=%s", dev->driver->name)) - return -ENOMEM; + /* + * TBD: _EJD support. + */ - envp[i] = NULL; + status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + return (-ENODEV); + } - return 0; + return (0); } -static struct kset_uevent_ops namespace_uevent_ops = { - .uevent = &namespace_uevent, -}; +static ssize_t +acpi_eject_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + int result; + int ret = count; + int islockable; + acpi_status status; + acpi_handle handle; + acpi_object_type type = 0; + struct acpi_device *acpi_device = to_acpi_device(d); -static struct kset acpi_namespace_kset = { - .kobj = { - .name = "namespace", - }, - .subsys = &acpi_subsys, - .ktype = &ktype_acpi_ns, - .uevent_ops = &namespace_uevent_ops, -}; + if ((!count) || (buf[0] != '1')) { + return -EINVAL; + } +#ifndef FORCE_EJECT + if (acpi_device->driver == NULL) { + ret = -ENODEV; + goto err; + } +#endif + status = acpi_get_type(acpi_device->handle, &type); + if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) { + ret = -ENODEV; + goto err; + } -static void acpi_device_register(struct acpi_device *device, - struct acpi_device *parent) -{ - int err; + islockable = acpi_device->flags.lockable; + handle = acpi_device->handle; - /* - * Linkage - * ------- - * Link this device to its parent and siblings. - */ - INIT_LIST_HEAD(&device->children); - INIT_LIST_HEAD(&device->node); - INIT_LIST_HEAD(&device->g_list); - INIT_LIST_HEAD(&device->wakeup_list); + result = acpi_bus_trim(acpi_device, 1); - spin_lock(&acpi_device_lock); - if (device->parent) { - list_add_tail(&device->node, &device->parent->children); - list_add_tail(&device->g_list, &device->parent->g_list); - } else - list_add_tail(&device->g_list, &acpi_device_list); - if (device->wakeup.flags.valid) - list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); - spin_unlock(&acpi_device_lock); + if (!result) + result = acpi_eject_operation(handle, islockable); - strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN); - if (parent) - device->kobj.parent = &parent->kobj; - device->kobj.ktype = &ktype_acpi_ns; - device->kobj.kset = &acpi_namespace_kset; - err = kobject_register(&device->kobj); - if (err < 0) - printk(KERN_WARNING "%s: kobject_register error: %d\n", - __FUNCTION__, err); - create_sysfs_device_files(device); + if (result) { + ret = -EBUSY; + } + err: + return ret; } -static void acpi_device_unregister(struct acpi_device *device, int type) -{ - spin_lock(&acpi_device_lock); - if (device->parent) { - list_del(&device->node); - list_del(&device->g_list); - } else - list_del(&device->g_list); +static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); - list_del(&device->wakeup_list); - - spin_unlock(&acpi_device_lock); +static ssize_t +acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); - acpi_detach_data(device->handle, acpi_bus_data_handler); - remove_sysfs_device_files(device); - kobject_unregister(&device->kobj); + return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id); } +static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); -void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) -{ +static ssize_t +acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; + int result; - /* TBD */ + result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); + if(result) + goto end; - return; + result = sprintf(buf, "%s\n", (char*)path.pointer); + kfree(path.pointer); + end: + return result; } +static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); -static int acpi_bus_get_power_flags(struct acpi_device *device) +static int acpi_device_setup_files(struct acpi_device *dev) { - acpi_status status = 0; - acpi_handle handle = NULL; - u32 i = 0; - - - /* - * Power Management Flags - */ - status = acpi_get_handle(device->handle, "_PSC", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.explicit_get = 1; - status = acpi_get_handle(device->handle, "_IRC", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.inrush_current = 1; + acpi_status status; + acpi_handle temp; + int result = 0; /* - * Enumerate supported power management states + * Devices gotten from FADT don't have a "path" attribute */ - for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { - struct acpi_device_power_state *ps = &device->power.states[i]; - char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; - - /* Evaluate "_PRx" to se if power resources are referenced */ - acpi_evaluate_reference(device->handle, object_name, NULL, - &ps->resources); - if (ps->resources.count) { - device->power.flags.power_resources = 1; - ps->flags.valid = 1; - } - - /* Evaluate "_PSx" to see if we can do explicit sets */ - object_name[2] = 'S'; - status = acpi_get_handle(device->handle, object_name, &handle); - if (ACPI_SUCCESS(status)) { - ps->flags.explicit_set = 1; - ps->flags.valid = 1; - } - - /* State is valid if we have some power control */ - if (ps->resources.count || ps->flags.explicit_set) - ps->flags.valid = 1; - - ps->power = -1; /* Unknown - driver assigned */ - ps->latency = -1; /* Unknown - driver assigned */ + if(dev->handle) { + result = device_create_file(&dev->dev, &dev_attr_path); + if(result) + goto end; } - /* Set defaults for D0 and D3 states (always valid) */ - device->power.states[ACPI_STATE_D0].flags.valid = 1; - device->power.states[ACPI_STATE_D0].power = 100; - device->power.states[ACPI_STATE_D3].flags.valid = 1; - device->power.states[ACPI_STATE_D3].power = 0; - - /* TBD: System wake support and resource requirements. */ - - device->power.state = ACPI_STATE_UNKNOWN; + if(dev->flags.hardware_id) { + result = device_create_file(&dev->dev, &dev_attr_hid); + if(result) + goto end; + } - return 0; + /* + * If device has _EJ0, 'eject' file is created that is used to trigger + * hot-removal function from userland. + */ + status = acpi_get_handle(dev->handle, "_EJ0", &temp); + if (ACPI_SUCCESS(status)) + result = device_create_file(&dev->dev, &dev_attr_eject); + end: + return result; } -int acpi_match_ids(struct acpi_device *device, char *ids) +static void acpi_device_remove_files(struct acpi_device *dev) { - if (device->flags.hardware_id) - if (strstr(ids, device->pnp.hardware_id)) - return 0; + acpi_status status; + acpi_handle temp; - if (device->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; - int i; + /* + * If device has _EJ0, 'eject' file is created that is used to trigger + * hot-removal function from userland. + */ + status = acpi_get_handle(dev->handle, "_EJ0", &temp); + if (ACPI_SUCCESS(status)) + device_remove_file(&dev->dev, &dev_attr_eject); - /* compare multiple _CID entries against driver ids */ - for (i = 0; i < cid_list->count; i++) { - if (strstr(ids, cid_list->id[i].value)) - return 0; - } - } - return -ENOENT; + if(dev->flags.hardware_id) + device_remove_file(&dev->dev, &dev_attr_hid); + if(dev->handle) + device_remove_file(&dev->dev, &dev_attr_path); } - -static acpi_status -acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, - union acpi_object *package) +/* -------------------------------------------------------------------------- + ACPI Bus operations + -------------------------------------------------------------------------- */ +static void acpi_device_release(struct device *dev) { - int i = 0; - union acpi_object *element = NULL; - - if (!device || !package || (package->package.count < 2)) - return AE_BAD_PARAMETER; - - element = &(package->package.elements[0]); - if (!element) - return AE_BAD_PARAMETER; - if (element->type == ACPI_TYPE_PACKAGE) { - if ((element->package.count < 2) || - (element->package.elements[0].type != - ACPI_TYPE_LOCAL_REFERENCE) - || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) - return AE_BAD_DATA; - device->wakeup.gpe_device = - element->package.elements[0].reference.handle; - device->wakeup.gpe_number = - (u32) element->package.elements[1].integer.value; - } else if (element->type == ACPI_TYPE_INTEGER) { - device->wakeup.gpe_number = element->integer.value; - } else - return AE_BAD_DATA; - - element = &(package->package.elements[1]); - if (element->type != ACPI_TYPE_INTEGER) { - return AE_BAD_DATA; - } - device->wakeup.sleep_state = element->integer.value; - - if ((package->package.count - 2) > ACPI_MAX_HANDLES) { - return AE_NO_MEMORY; - } - device->wakeup.resources.count = package->package.count - 2; - for (i = 0; i < device->wakeup.resources.count; i++) { - element = &(package->package.elements[i + 2]); - if (element->type != ACPI_TYPE_ANY) { - return AE_BAD_DATA; - } - - device->wakeup.resources.handles[i] = element->reference.handle; - } + struct acpi_device *acpi_dev = to_acpi_device(dev); - return AE_OK; + kfree(acpi_dev->pnp.cid_list); + kfree(acpi_dev); } -static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) +static int acpi_device_suspend(struct device *dev, pm_message_t state) { - acpi_status status = 0; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *package = NULL; - + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; - /* _PRW */ - status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); - goto end; - } - - package = (union acpi_object *)buffer.pointer; - status = acpi_bus_extract_wakeup_device_power_package(device, package); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); - goto end; - } - - kfree(buffer.pointer); - - device->wakeup.flags.valid = 1; - /* Power button, Lid switch always enable wakeup */ - if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E")) - device->wakeup.flags.run_wake = 1; - - end: - if (ACPI_FAILURE(status)) - device->flags.wake_capable = 0; + if (acpi_drv && acpi_drv->ops.suspend) + return acpi_drv->ops.suspend(acpi_dev, state); return 0; } -/* -------------------------------------------------------------------------- - ACPI sysfs device file support - -------------------------------------------------------------------------- */ -static ssize_t acpi_eject_store(struct acpi_device *device, - const char *buf, size_t count); - -#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \ -static struct acpi_device_attribute acpi_device_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) +static int acpi_device_resume(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; -ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); + if (acpi_drv && acpi_drv->ops.resume) + return acpi_drv->ops.resume(acpi_dev); + return 0; +} -/** - * setup_sys_fs_device_files - sets up the device files under device namespace - * @dev: acpi_device object - * @func: function pointer to create or destroy the device file - */ -static void -setup_sys_fs_device_files(struct acpi_device *dev, - acpi_device_sysfs_files * func) +static int acpi_bus_match(struct device *dev, struct device_driver *drv) { - acpi_status status; - acpi_handle temp = NULL; + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(drv); - /* - * If device has _EJ0, 'eject' file is created that is used to trigger - * hot-removal function from userland. - */ - status = acpi_get_handle(dev->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) - (*(func)) (&dev->kobj, &acpi_device_attr_eject.attr); + return !acpi_match_ids(acpi_dev, acpi_drv->ids); } -static int acpi_eject_operation(acpi_handle handle, int lockable) +static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) { - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status = AE_OK; + struct acpi_device *acpi_dev = to_acpi_device(dev); + int i = 0, length = 0, ret = 0; - /* - * TBD: evaluate _PS3? - */ + if (acpi_dev->flags.hardware_id) + ret = add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "HWID=%s", acpi_dev->pnp.hardware_id); + if (ret) + return -ENOMEM; + if (acpi_dev->flags.compatible_ids) { + int j; + struct acpi_compatible_id_list *cid_list; + + cid_list = acpi_dev->pnp.cid_list; + + for (j = 0; j < cid_list->count; j++) { + ret = add_uevent_var(envp, num_envp, &i, buffer, + buffer_size, &length, "COMPTID=%s", + cid_list->id[j].value); + if (ret) + return -ENOMEM; + } + } - if (lockable) { - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 0; - acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); + envp[i] = NULL; + return 0; +} + +static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); +static int acpi_start_single_object(struct acpi_device *); +static int acpi_device_probe(struct device * dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); + int ret; + + ret = acpi_bus_driver_init(acpi_dev, acpi_drv); + if (!ret) { + if (acpi_dev->bus_ops.acpi_op_start) + acpi_start_single_object(acpi_dev); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Found driver [%s] for device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + get_device(dev); + } + return ret; +} + +static int acpi_device_remove(struct device * dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv) { + 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); } + acpi_dev->driver = NULL; + acpi_driver_data(dev) = NULL; - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; + put_device(dev); + return 0; +} - /* - * TBD: _EJD support. - */ +static void acpi_device_shutdown(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; - status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - return (-ENODEV); - } + if (acpi_drv && acpi_drv->ops.shutdown) + acpi_drv->ops.shutdown(acpi_dev); - return (0); + return ; } -static ssize_t -acpi_eject_store(struct acpi_device *device, const char *buf, size_t count) +static struct bus_type acpi_bus_type = { + .name = "acpi", + .suspend = acpi_device_suspend, + .resume = acpi_device_resume, + .shutdown = acpi_device_shutdown, + .match = acpi_bus_match, + .probe = acpi_device_probe, + .remove = acpi_device_remove, + .uevent = acpi_device_uevent, +}; + +static int acpi_device_register(struct acpi_device *device, + struct acpi_device *parent) { int result; - int ret = count; - int islockable; - acpi_status status; - acpi_handle handle; - acpi_object_type type = 0; + struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; + int found = 0; + /* + * Linkage + * ------- + * Link this device to its parent and siblings. + */ + INIT_LIST_HEAD(&device->children); + INIT_LIST_HEAD(&device->node); + INIT_LIST_HEAD(&device->g_list); + INIT_LIST_HEAD(&device->wakeup_list); - if ((!count) || (buf[0] != '1')) { - return -EINVAL; + new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); + if (!new_bus_id) { + printk(KERN_ERR PREFIX "Memory allocation error\n"); + return -ENOMEM; } -#ifndef FORCE_EJECT - if (device->driver == NULL) { - ret = -ENODEV; - goto err; + + spin_lock(&acpi_device_lock); + /* + * Find suitable bus_id and instance number in acpi_bus_id_list + * If failed, create one and link it into acpi_bus_id_list + */ + list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { + if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) { + acpi_device_bus_id->instance_no ++; + found = 1; + kfree(new_bus_id); + break; + } } -#endif - status = acpi_get_type(device->handle, &type); - if (ACPI_FAILURE(status) || (!device->flags.ejectable)) { - ret = -ENODEV; - goto err; + if(!found) { + acpi_device_bus_id = new_bus_id; + strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device"); + acpi_device_bus_id->instance_no = 0; + list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); } + sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); - islockable = device->flags.lockable; - handle = device->handle; - - result = acpi_bus_trim(device, 1); - - if (!result) - result = acpi_eject_operation(handle, islockable); + if (device->parent) { + list_add_tail(&device->node, &device->parent->children); + list_add_tail(&device->g_list, &device->parent->g_list); + } else + list_add_tail(&device->g_list, &acpi_device_list); + if (device->wakeup.flags.valid) + list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); + spin_unlock(&acpi_device_lock); - if (result) { - ret = -EBUSY; + if (device->parent) + device->dev.parent = &parent->dev; + device->dev.bus = &acpi_bus_type; + device_initialize(&device->dev); + device->dev.release = &acpi_device_release; + result = device_add(&device->dev); + if(result) { + printk("Error adding device %s", device->dev.bus_id); + goto end; } - err: - return ret; -} -/* -------------------------------------------------------------------------- - Performance Management - -------------------------------------------------------------------------- */ + result = acpi_device_setup_files(device); + if(result) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id)); -static int acpi_bus_get_perf_flags(struct acpi_device *device) -{ - device->performance.state = ACPI_STATE_UNKNOWN; + device->removal_type = ACPI_BUS_REMOVAL_NORMAL; return 0; + end: + spin_lock(&acpi_device_lock); + if (device->parent) { + list_del(&device->node); + list_del(&device->g_list); + } else + list_del(&device->g_list); + list_del(&device->wakeup_list); + spin_unlock(&acpi_device_lock); + return result; } -/* -------------------------------------------------------------------------- - Driver Management - -------------------------------------------------------------------------- */ +static void acpi_device_unregister(struct acpi_device *device, int type) +{ + spin_lock(&acpi_device_lock); + if (device->parent) { + list_del(&device->node); + list_del(&device->g_list); + } else + list_del(&device->g_list); + + list_del(&device->wakeup_list); + spin_unlock(&acpi_device_lock); -static LIST_HEAD(acpi_bus_drivers); + acpi_detach_data(device->handle, acpi_bus_data_handler); -/** - * acpi_bus_match - match device IDs to driver's supported IDs - * @device: the device that we are trying to match to a driver - * @driver: driver whose device id table is being checked - * - * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it - * matches the specified driver's criteria. - */ -static int -acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver) -{ - if (driver && driver->ops.match) - return driver->ops.match(device, driver); - return acpi_match_ids(device, driver->ids); + acpi_device_remove_files(device); + device_unregister(&device->dev); } +/* -------------------------------------------------------------------------- + Driver Management + -------------------------------------------------------------------------- */ /** * acpi_bus_driver_init - add a device to a driver * @device: the device to add and initialize * @driver: driver for the device * * Used to initialize a device via its device driver. Called whenever a - * driver is bound to a device. Invokes the driver's add() and start() ops. + * driver is bound to a device. Invokes the driver's add() ops. */ static int acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) @@ -535,162 +473,246 @@ static int acpi_start_single_object(stru return result; } -static void acpi_driver_attach(struct acpi_driver *drv) +/** + * acpi_bus_register_driver - register a driver with the ACPI bus + * @driver: driver being registered + * + * Registers a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and binds. Returns zero for + * success or a negative error status for failure. + */ +int acpi_bus_register_driver(struct acpi_driver *driver) { - struct list_head *node, *next; + int ret; + if (acpi_disabled) + return -ENODEV; + driver->drv.name = driver->name; + driver->drv.bus = &acpi_bus_type; + driver->drv.owner = driver->owner; - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, g_list); + ret = driver_register(&driver->drv); + return ret; +} - if (dev->driver || !dev->status.present) - continue; - spin_unlock(&acpi_device_lock); +EXPORT_SYMBOL(acpi_bus_register_driver); - if (!acpi_bus_match(dev, drv)) { - if (!acpi_bus_driver_init(dev, drv)) { - acpi_start_single_object(dev); - atomic_inc(&drv->references); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found driver [%s] for device [%s]\n", - drv->name, dev->pnp.bus_id)); - } +/** + * acpi_bus_unregister_driver - unregisters a driver with the APIC bus + * @driver: driver to unregister + * + * Unregisters a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and unbinds. + */ +void acpi_bus_unregister_driver(struct acpi_driver *driver) +{ + driver_unregister(&driver->drv); +} + +EXPORT_SYMBOL(acpi_bus_unregister_driver); + +/* -------------------------------------------------------------------------- + Device Enumeration + -------------------------------------------------------------------------- */ +acpi_status +acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) +{ + acpi_status status; + acpi_handle tmp; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + + status = acpi_get_handle(handle, "_EJD", &tmp); + if (ACPI_FAILURE(status)) + return status; + + status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); + if (ACPI_SUCCESS(status)) { + obj = buffer.pointer; + status = acpi_get_handle(NULL, obj->string.pointer, ejd); + kfree(buffer.pointer); + } + return status; +} +EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); + +void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) +{ + + /* TBD */ + + return; +} + +int acpi_match_ids(struct acpi_device *device, char *ids) +{ + if (device->flags.hardware_id) + if (strstr(ids, device->pnp.hardware_id)) + return 0; + + if (device->flags.compatible_ids) { + struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; + int i; + + /* compare multiple _CID entries against driver ids */ + for (i = 0; i < cid_list->count; i++) { + if (strstr(ids, cid_list->id[i].value)) + return 0; } - spin_lock(&acpi_device_lock); } - spin_unlock(&acpi_device_lock); + return -ENOENT; +} + +static int acpi_bus_get_perf_flags(struct acpi_device *device) +{ + device->performance.state = ACPI_STATE_UNKNOWN; + return 0; } -static void acpi_driver_detach(struct acpi_driver *drv) +static acpi_status +acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, + union acpi_object *package) { - struct list_head *node, *next; + int i = 0; + union acpi_object *element = NULL; + if (!device || !package || (package->package.count < 2)) + return AE_BAD_PARAMETER; - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, g_list); - - if (dev->driver == drv) { - spin_unlock(&acpi_device_lock); - if (drv->ops.remove) - drv->ops.remove(dev, ACPI_BUS_REMOVAL_NORMAL); - spin_lock(&acpi_device_lock); - dev->driver = NULL; - dev->driver_data = NULL; - atomic_dec(&drv->references); + element = &(package->package.elements[0]); + if (!element) + return AE_BAD_PARAMETER; + if (element->type == ACPI_TYPE_PACKAGE) { + if ((element->package.count < 2) || + (element->package.elements[0].type != + ACPI_TYPE_LOCAL_REFERENCE) + || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) + return AE_BAD_DATA; + device->wakeup.gpe_device = + element->package.elements[0].reference.handle; + device->wakeup.gpe_number = + (u32) element->package.elements[1].integer.value; + } else if (element->type == ACPI_TYPE_INTEGER) { + device->wakeup.gpe_number = element->integer.value; + } else + return AE_BAD_DATA; + + element = &(package->package.elements[1]); + if (element->type != ACPI_TYPE_INTEGER) { + return AE_BAD_DATA; + } + device->wakeup.sleep_state = element->integer.value; + + if ((package->package.count - 2) > ACPI_MAX_HANDLES) { + return AE_NO_MEMORY; + } + device->wakeup.resources.count = package->package.count - 2; + for (i = 0; i < device->wakeup.resources.count; i++) { + element = &(package->package.elements[i + 2]); + if (element->type != ACPI_TYPE_ANY) { + return AE_BAD_DATA; } + + device->wakeup.resources.handles[i] = element->reference.handle; + } + + return AE_OK; +} + +static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) +{ + acpi_status status = 0; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *package = NULL; + + + /* _PRW */ + status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); + goto end; } - spin_unlock(&acpi_device_lock); -} -/** - * acpi_bus_register_driver - register a driver with the ACPI bus - * @driver: driver being registered - * - * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. Returns zero for - * success or a negative error status for failure. - */ -int acpi_bus_register_driver(struct acpi_driver *driver) -{ + package = (union acpi_object *)buffer.pointer; + status = acpi_bus_extract_wakeup_device_power_package(device, package); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); + goto end; + } - if (acpi_disabled) - return -ENODEV; + kfree(buffer.pointer); - spin_lock(&acpi_device_lock); - list_add_tail(&driver->node, &acpi_bus_drivers); - spin_unlock(&acpi_device_lock); - acpi_driver_attach(driver); + device->wakeup.flags.valid = 1; + /* Power button, Lid switch always enable wakeup */ + if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E")) + device->wakeup.flags.run_wake = 1; + end: + if (ACPI_FAILURE(status)) + device->flags.wake_capable = 0; return 0; } -EXPORT_SYMBOL(acpi_bus_register_driver); - -/** - * acpi_bus_unregister_driver - unregisters a driver with the APIC bus - * @driver: driver to unregister - * - * Unregisters a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and unbinds. - */ -void acpi_bus_unregister_driver(struct acpi_driver *driver) +static int acpi_bus_get_power_flags(struct acpi_device *device) { - acpi_driver_detach(driver); + acpi_status status = 0; + acpi_handle handle = NULL; + u32 i = 0; - if (!atomic_read(&driver->references)) { - spin_lock(&acpi_device_lock); - list_del_init(&driver->node); - spin_unlock(&acpi_device_lock); - } - return; -} -EXPORT_SYMBOL(acpi_bus_unregister_driver); + /* + * Power Management Flags + */ + status = acpi_get_handle(device->handle, "_PSC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.explicit_get = 1; + status = acpi_get_handle(device->handle, "_IRC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.inrush_current = 1; -/** - * acpi_bus_find_driver - check if there is a driver installed for the device - * @device: device that we are trying to find a supporting driver for - * - * Parses the list of registered drivers looking for a driver applicable for - * the specified device. - */ -static int acpi_bus_find_driver(struct acpi_device *device) -{ - int result = 0; - struct list_head *node, *next; + /* + * Enumerate supported power management states + */ + for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { + struct acpi_device_power_state *ps = &device->power.states[i]; + char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; + /* Evaluate "_PRx" to se if power resources are referenced */ + acpi_evaluate_reference(device->handle, object_name, NULL, + &ps->resources); + if (ps->resources.count) { + device->power.flags.power_resources = 1; + ps->flags.valid = 1; + } - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_bus_drivers) { - struct acpi_driver *driver = - container_of(node, struct acpi_driver, node); - - atomic_inc(&driver->references); - spin_unlock(&acpi_device_lock); - if (!acpi_bus_match(device, driver)) { - result = acpi_bus_driver_init(device, driver); - if (!result) - goto Done; + /* Evaluate "_PSx" to see if we can do explicit sets */ + object_name[2] = 'S'; + status = acpi_get_handle(device->handle, object_name, &handle); + if (ACPI_SUCCESS(status)) { + ps->flags.explicit_set = 1; + ps->flags.valid = 1; } - atomic_dec(&driver->references); - spin_lock(&acpi_device_lock); - } - spin_unlock(&acpi_device_lock); - Done: - return result; -} + /* State is valid if we have some power control */ + if (ps->resources.count || ps->flags.explicit_set) + ps->flags.valid = 1; -/* -------------------------------------------------------------------------- - Device Enumeration - -------------------------------------------------------------------------- */ + ps->power = -1; /* Unknown - driver assigned */ + ps->latency = -1; /* Unknown - driver assigned */ + } -acpi_status -acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) -{ - acpi_status status; - acpi_handle tmp; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *obj; + /* Set defaults for D0 and D3 states (always valid) */ + device->power.states[ACPI_STATE_D0].flags.valid = 1; + device->power.states[ACPI_STATE_D0].power = 100; + device->power.states[ACPI_STATE_D3].flags.valid = 1; + device->power.states[ACPI_STATE_D3].power = 0; - status = acpi_get_handle(handle, "_EJD", &tmp); - if (ACPI_FAILURE(status)) - return status; + /* TBD: System wake support and resource requirements. */ - status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); - if (ACPI_SUCCESS(status)) { - obj = buffer.pointer; - status = acpi_get_handle(NULL, obj->string.pointer, ejd); - kfree(buffer.pointer); - } - return status; -} -EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); + device->power.state = ACPI_STATE_UNKNOWN; + return 0; +} static int acpi_bus_get_flags(struct acpi_device *device) { @@ -782,6 +804,75 @@ static void acpi_device_get_busid(struct } } +static int +acpi_video_bus_match(struct acpi_device *device) +{ + acpi_handle h_dummy1; + acpi_handle h_dummy2; + acpi_handle h_dummy3; + + + if (!device) + return -EINVAL; + + /* Since there is no HID, CID for ACPI Video drivers, we have + * to check well known required nodes for each feature we support. + */ + + /* Does this device able to support video switching ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2))) + return 0; + + /* Does this device able to retrieve a video ROM ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1))) + return 0; + + /* Does this device able to configure which video head to be POSTed ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3))) + return 0; + + return -ENODEV; +} + +/* + * acpi_bay_match - see if a device is an ejectable driver bay + * + * If an acpi object is ejectable and has one of the ACPI ATA methods defined, + * then we can safely call it an ejectable drive bay + */ +static int acpi_bay_match(struct acpi_device *device){ + acpi_status status; + acpi_handle handle; + acpi_handle tmp; + acpi_handle phandle; + + handle = device->handle; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) + return -ENODEV; + + if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + return 0; + + if (acpi_get_parent(handle, &phandle)) + return -ENODEV; + + if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp)))) + return 0; + + return -ENODEV; +} + static void acpi_device_set_id(struct acpi_device *device, struct acpi_device *parent, acpi_handle handle, int type) @@ -812,6 +903,16 @@ static void acpi_device_set_id(struct ac device->pnp.bus_address = info->address; device->flags.bus_address = 1; } + + if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){ + status = acpi_video_bus_match(device); + if(ACPI_SUCCESS(status)) + hid = ACPI_VIDEO_HID; + + status = acpi_bay_match(device); + if (ACPI_SUCCESS(status)) + hid = ACPI_BAY_HID; + } break; case ACPI_BUS_TYPE_POWER: hid = ACPI_POWER_HID; @@ -933,41 +1034,22 @@ static void acpi_device_get_debug_info(s static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) { - int result = 0; - struct acpi_driver *driver; - - if (!dev) return -EINVAL; - driver = dev->driver; - - if ((driver) && (driver->ops.remove)) { - - if (driver->ops.stop) { - result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT); - if (result) - return result; - } - - result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT); - if (result) { - return result; - } - - atomic_dec(&dev->driver->references); - dev->driver = NULL; - acpi_driver_data(dev) = NULL; - } + dev->removal_type = ACPI_BUS_REMOVAL_EJECT; + device_release_driver(&dev->dev); if (!rmdevice) return 0; + /* + * unbind _ADR-Based Devices when hot removal + */ if (dev->flags.bus_address) { if ((dev->parent) && (dev->parent->ops.unbind)) dev->parent->ops.unbind(dev); } - acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT); return 0; @@ -975,7 +1057,8 @@ static int acpi_bus_remove(struct acpi_d static int acpi_add_single_object(struct acpi_device **child, - struct acpi_device *parent, acpi_handle handle, int type) + struct acpi_device *parent, acpi_handle handle, int type, + struct acpi_bus_ops *ops) { int result = 0; struct acpi_device *device = NULL; @@ -992,6 +1075,8 @@ acpi_add_single_object(struct acpi_devic device->handle = handle; device->parent = parent; + device->bus_ops = *ops; /* workround for not call .start */ + acpi_device_get_busid(device, handle, type); @@ -1078,31 +1163,16 @@ acpi_add_single_object(struct acpi_devic acpi_device_get_debug_info(device, handle, type); - acpi_device_register(device, parent); + result = acpi_device_register(device, parent); /* - * Bind _ADR-Based Devices - * ----------------------- - * If there's a a bus address (_ADR) then we utilize the parent's - * 'bind' function (if exists) to bind the ACPI- and natively- - * enumerated device representations. + * Bind _ADR-Based Devices when hot add */ if (device->flags.bus_address) { if (device->parent && device->parent->ops.bind) device->parent->ops.bind(device); } - /* - * Locate & Attach Driver - * ---------------------- - * If there's a hardware id (_HID) or compatible ids (_CID) we check - * to see if there's a driver installed for this kind of device. Note - * that drivers can install before or after a device is enumerated. - * - * TBD: Assumes LDM provides driver hot-plug capability. - */ - acpi_bus_find_driver(device); - end: if (!result) *child = device; @@ -1188,14 +1258,14 @@ static int acpi_bus_scan(struct acpi_dev if (ops->acpi_op_add) status = acpi_add_single_object(&child, parent, - chandle, type); + chandle, type, ops); else status = acpi_bus_get_device(chandle, &child); if (ACPI_FAILURE(status)) continue; - if (ops->acpi_op_start) { + if (ops->acpi_op_start && !(ops->acpi_op_add)) { status = acpi_start_single_object(child); if (ACPI_FAILURE(status)) continue; @@ -1233,13 +1303,13 @@ acpi_bus_add(struct acpi_device **child, int result; struct acpi_bus_ops ops; + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; - result = acpi_add_single_object(child, parent, handle, type); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; + result = acpi_add_single_object(child, parent, handle, type, &ops); + if (!result) result = acpi_bus_scan(*child, &ops); - } + return result; } @@ -1325,127 +1395,35 @@ static int acpi_bus_scan_fixed(struct ac { int result = 0; struct acpi_device *device = NULL; - + struct acpi_bus_ops ops; if (!root) return -ENODEV; + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; + /* * Enumerate all fixed-feature devices. */ if (acpi_fadt.pwr_button == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, - ACPI_BUS_TYPE_POWER_BUTTON); - if (!result) - result = acpi_start_single_object(device); + ACPI_BUS_TYPE_POWER_BUTTON, + &ops); } if (acpi_fadt.sleep_button == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, - ACPI_BUS_TYPE_SLEEP_BUTTON); - if (!result) - result = acpi_start_single_object(device); + ACPI_BUS_TYPE_SLEEP_BUTTON, + &ops); } return result; } - -static inline struct acpi_device * to_acpi_dev(struct device * dev) -{ - return container_of(dev, struct acpi_device, dev); -} - - -static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state) -{ - struct acpi_device * dev, * next; - int result; - - spin_lock(&acpi_device_lock); - list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) { - if (dev->driver && dev->driver->ops.suspend) { - spin_unlock(&acpi_device_lock); - result = dev->driver->ops.suspend(dev, 0); - if (result) { - printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n", - acpi_device_name(dev), - acpi_device_bid(dev), result); - } - spin_lock(&acpi_device_lock); - } - } - spin_unlock(&acpi_device_lock); - return 0; -} - - -static int acpi_device_suspend(struct device * dev, pm_message_t state) -{ - struct acpi_device * acpi_dev = to_acpi_dev(dev); - - /* - * For now, we should only register 1 generic device - - * the ACPI root device - and from there, we walk the - * tree of ACPI devices to suspend each one using the - * ACPI driver methods. - */ - if (acpi_dev->handle == ACPI_ROOT_OBJECT) - root_suspend(acpi_dev, state); - return 0; -} - - - -static int root_resume(struct acpi_device * acpi_dev) -{ - struct acpi_device * dev, * next; - int result; - - spin_lock(&acpi_device_lock); - list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) { - if (dev->driver && dev->driver->ops.resume) { - spin_unlock(&acpi_device_lock); - result = dev->driver->ops.resume(dev, 0); - if (result) { - printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n", - acpi_device_name(dev), - acpi_device_bid(dev), result); - } - spin_lock(&acpi_device_lock); - } - } - spin_unlock(&acpi_device_lock); - return 0; -} - - -static int acpi_device_resume(struct device * dev) -{ - struct acpi_device * acpi_dev = to_acpi_dev(dev); - - /* - * For now, we should only register 1 generic device - - * the ACPI root device - and from there, we walk the - * tree of ACPI devices to resume each one using the - * ACPI driver methods. - */ - if (acpi_dev->handle == ACPI_ROOT_OBJECT) - root_resume(acpi_dev); - return 0; -} - - -static struct bus_type acpi_bus_type = { - .name = "acpi", - .suspend = acpi_device_suspend, - .resume = acpi_device_resume, -}; - - - static int __init acpi_scan_init(void) { int result; @@ -1455,9 +1433,9 @@ static int __init acpi_scan_init(void) if (acpi_disabled) return 0; - result = kset_register(&acpi_namespace_kset); - if (result < 0) - printk(KERN_ERR PREFIX "kset_register error: %d\n", result); + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; result = bus_register(&acpi_bus_type); if (result) { @@ -1469,32 +1447,16 @@ static int __init acpi_scan_init(void) * Create the root device in the bus's device tree */ result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, - ACPI_BUS_TYPE_SYSTEM); + ACPI_BUS_TYPE_SYSTEM, &ops); if (result) goto Done; - result = acpi_start_single_object(acpi_root); - if (result) - goto Done; - - acpi_root->dev.bus = &acpi_bus_type; - snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name); - result = device_register(&acpi_root->dev); - if (result) { - /* We don't want to quit even if we failed to add suspend/resume */ - printk(KERN_ERR PREFIX "Could not register device\n"); - } - /* * Enumerate devices in the ACPI namespace. */ result = acpi_bus_scan_fixed(acpi_root); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; - ops.acpi_op_start = 1; + if (!result) result = acpi_bus_scan(acpi_root, &ops); - } if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); diff -puN drivers/acpi/tables.c~git-acpi drivers/acpi/tables.c --- a/drivers/acpi/tables.c~git-acpi +++ a/drivers/acpi/tables.c @@ -75,6 +75,14 @@ static unsigned long sdt_count; /* Table static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata; +/* + * When a BIOS erroneously provides multiple copies of a 'unique' table, + * Linux must decide which one to use. The default is 0, use the first, + * but some machines have been shown to need "acpi_parse_multi_table=1" + * to use the second. + */ +static int acpi_parse_multi_table; + void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr) { char *name = NULL; @@ -304,55 +312,70 @@ acpi_get_table_header_early(enum acpi_ta return 0; } +/* + * acpi_table_parse_entries(id, size, entry_id, handler, max) + * + * In SDT, match table with 'id'. + * If BIOS bug results in multiple tables of 'id', use the last. + * to match acpi_table_parse(), which warned about it. + * + * Within that table, run 'handler' on all entries matching 'entry_id' + * + * return 0 on success finding table and running handler + * return negative in all other cases + */ int __init -acpi_table_parse_madt_family(enum acpi_table_id id, - unsigned long madt_size, +acpi_table_parse_entries(enum acpi_table_id id, + unsigned long table_size, int entry_id, - acpi_madt_entry_handler handler, + acpi_table_entry_handler handler, unsigned int max_entries) { - void *madt = NULL; + void *table_start = NULL; acpi_table_entry_header *entry; unsigned int count = 0; - unsigned long madt_end; + unsigned long table_end; unsigned int i; + unsigned int index; - if (!handler) - return -EINVAL; - - /* Locate the MADT (if exists). There should only be one. */ + BUG_ON(!handler); for (i = 0; i < sdt_count; i++) { if (sdt_entry[i].id != id) continue; - madt = (void *) - __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size); - if (!madt) { - printk(KERN_WARNING PREFIX "Unable to map %s\n", - acpi_table_signatures[id]); - return -ENODEV; - } - break; + + index = i; + count++; + if (count > acpi_parse_multi_table) + break; } - if (!madt) { + if (count == 0) { printk(KERN_WARNING PREFIX "%s not present\n", acpi_table_signatures[id]); return -ENODEV; } - madt_end = (unsigned long)madt + sdt_entry[i].size; + table_start = (void *) + __acpi_map_table(sdt_entry[index].pa, sdt_entry[index].size); + if (!table_start) { + printk(KERN_WARNING PREFIX "Unable to map %s\n", + acpi_table_signatures[id]); + return -ENODEV; + } + + table_end = (unsigned long)table_start + sdt_entry[i].size; /* Parse all entries looking for a match. */ entry = (acpi_table_entry_header *) - ((unsigned long)madt + madt_size); + ((unsigned long)table_start + table_size); while (((unsigned long)entry) + sizeof(acpi_table_entry_header) < - madt_end) { + table_end) { if (entry->type == entry_id && (!max_entries || count++ < max_entries)) - if (handler(entry, madt_end)) + if (handler(entry, table_end)) return -EINVAL; entry = (acpi_table_entry_header *) @@ -369,35 +392,64 @@ acpi_table_parse_madt_family(enum acpi_t int __init acpi_table_parse_madt(enum acpi_madt_entry_id id, - acpi_madt_entry_handler handler, unsigned int max_entries) + acpi_table_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_APIC, + return acpi_table_parse_entries(ACPI_APIC, sizeof(struct acpi_table_madt), id, handler, max_entries); } +/* + * acpi_table_parse(id, handler) + * + * Find table 'id' in SDT, run handler on table + * + * If BIOS bug results in multiple matches, warn and use last. + * + * Return 0 on match + * Return non-0 on no match + */ int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler) { - int count = 0; - unsigned int i = 0; + unsigned int i; + unsigned int index; + unsigned int count = 0; - if (!handler) - return -EINVAL; + BUG_ON(!handler); for (i = 0; i < sdt_count; i++) { if (sdt_entry[i].id != id) continue; - count++; - if (count == 1) - handler(sdt_entry[i].pa, sdt_entry[i].size); - else + if (count <= acpi_parse_multi_table) { + index = i; + if (count > 0) + printk(KERN_WARNING PREFIX + "Duplicate %s #%d parsed\n", + acpi_table_signatures[id], + count); + } else { + printk(KERN_WARNING PREFIX + "Duplicate %s detected\n", + acpi_table_signatures[id]); printk(KERN_WARNING PREFIX - "%d duplicate %s table ignored.\n", count, - acpi_table_signatures[id]); + "Boot with \"acpi_parse_multi_table=%d\"\n" + "and report results to " + "linux-acpi@vger.kernel.org\n", + count); + } + count++; + } + if (count == 0) + return -1; - return count; + if (count > 1) + printk(KERN_NOTICE PREFIX "Parsing #%d %s\n", + count, acpi_table_signatures[id]); + + handler(sdt_entry[index].pa, sdt_entry[index].size); + return 0; } static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp) @@ -619,3 +671,15 @@ int __init acpi_table_init(void) return 0; } +static int __init acpi_parse_multi_table_setup(char *str) { + + acpi_parse_multi_table = simple_strtoul(str, NULL, 0); + + printk(KERN_NOTICE PREFIX "will parse #%d if duplicate tables.\n", + acpi_parse_multi_table); + + return 0; +} + +early_param("acpi_parse_multi_table", acpi_parse_multi_table_setup); + diff -puN drivers/acpi/thermal.c~git-acpi drivers/acpi/thermal.c --- a/drivers/acpi/thermal.c~git-acpi +++ a/drivers/acpi/thermal.c @@ -82,7 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone poll static int acpi_thermal_add(struct acpi_device *device); static int acpi_thermal_remove(struct acpi_device *device, int type); -static int acpi_thermal_resume(struct acpi_device *device, int state); +static int acpi_thermal_resume(struct acpi_device *device); static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file); @@ -1353,7 +1353,7 @@ static int acpi_thermal_remove(struct ac return 0; } -static int acpi_thermal_resume(struct acpi_device *device, int state) +static int acpi_thermal_resume(struct acpi_device *device) { struct acpi_thermal *tz = NULL; int i; diff -puN drivers/acpi/video.c~git-acpi drivers/acpi/video.c --- a/drivers/acpi/video.c~git-acpi +++ a/drivers/acpi/video.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -56,6 +57,12 @@ #define ACPI_VIDEO_HEAD_INVALID (~0u - 1) #define ACPI_VIDEO_HEAD_END (~0u) +#define MAX_NAME_LEN 20 + +#define ACPI_VIDEO_DISPLAY_CRT 1 +#define ACPI_VIDEO_DISPLAY_TV 2 +#define ACPI_VIDEO_DISPLAY_DVI 3 +#define ACPI_VIDEO_DISPLAY_LCD 4 #define _COMPONENT ACPI_VIDEO_COMPONENT ACPI_MODULE_NAME("acpi_video") @@ -66,16 +73,14 @@ MODULE_LICENSE("GPL"); static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); -static int acpi_video_bus_match(struct acpi_device *device, - struct acpi_driver *driver); static struct acpi_driver acpi_video_bus = { .name = ACPI_VIDEO_DRIVER_NAME, .class = ACPI_VIDEO_CLASS, + .ids = ACPI_VIDEO_HID, .ops = { .add = acpi_video_bus_add, .remove = acpi_video_bus_remove, - .match = acpi_video_bus_match, }, }; @@ -133,20 +138,21 @@ struct acpi_video_device_flags { u8 crt:1; u8 lcd:1; u8 tvout:1; + u8 dvi:1; u8 bios:1; u8 unknown:1; - u8 reserved:3; + u8 reserved:2; }; struct acpi_video_device_cap { u8 _ADR:1; /*Return the unique ID */ u8 _BCL:1; /*Query list of brightness control levels supported */ u8 _BCM:1; /*Set the brightness level */ + u8 _BQC:1; /* Get current brightness level */ u8 _DDC:1; /*Return the EDID for this device */ u8 _DCS:1; /*Return status of output device */ u8 _DGS:1; /*Query graphics state */ u8 _DSS:1; /*Device state set */ - u8 _reserved:1; }; struct acpi_video_device_brightness { @@ -163,6 +169,8 @@ struct acpi_video_device { struct acpi_video_bus *video; struct acpi_device *dev; struct acpi_video_device_brightness *brightness; + struct backlight_device *backlight; + struct backlight_properties *data; }; /* bus */ @@ -257,11 +265,35 @@ static void acpi_video_device_bind(struc struct acpi_video_device *device); static int acpi_video_device_enumerate(struct acpi_video_bus *video); static int acpi_video_switch_output(struct acpi_video_bus *video, int event); +static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, + int level); +static int acpi_video_device_lcd_get_level_current( + struct acpi_video_device *device, + unsigned long *level); static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event); static void acpi_video_switch_brightness(struct acpi_video_device *device, int event); +/*backlight device sysfs support*/ +static int acpi_video_get_brightness(struct backlight_device *bd) +{ + unsigned long cur_level; + struct acpi_video_device *vd = + (struct acpi_video_device *)class_get_devdata(&bd->class_dev); + acpi_video_device_lcd_get_level_current(vd, &cur_level); + return (int) cur_level; +} + +static int acpi_video_set_brightness(struct backlight_device *bd) +{ + int request_level = bd->props->brightness; + struct acpi_video_device *vd = + (struct acpi_video_device *)class_get_devdata(&bd->class_dev); + acpi_video_device_lcd_set_level(vd, request_level); + return 0; +} + /* -------------------------------------------------------------------------- Video Management -------------------------------------------------------------------------- */ @@ -499,6 +531,7 @@ static void acpi_video_device_find_cap(s acpi_integer status; acpi_handle h_dummy1; int i; + u32 max_level = 0; union acpi_object *obj = NULL; struct acpi_video_device_brightness *br = NULL; @@ -514,6 +547,8 @@ static void acpi_video_device_find_cap(s if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) { device->cap._BCM = 1; } + if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) + device->cap._BQC = 1; if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { device->cap._DDC = 1; } @@ -550,6 +585,8 @@ static void acpi_video_device_find_cap(s continue; } br->levels[count] = (u32) o->integer.value; + if (br->levels[count] > max_level) + max_level = br->levels[count]; count++; } out: @@ -568,6 +605,37 @@ static void acpi_video_device_find_cap(s kfree(obj); + if (device->cap._BCL && device->cap._BCM && device->cap._BQC){ + unsigned long tmp; + static int count = 0; + char *name; + struct backlight_properties *acpi_video_data; + + name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); + if (!name) + return; + + acpi_video_data = kzalloc( + sizeof(struct backlight_properties), + GFP_KERNEL); + if (!acpi_video_data){ + kfree(name); + return; + } + acpi_video_data->owner = THIS_MODULE; + acpi_video_data->get_brightness = + acpi_video_get_brightness; + acpi_video_data->update_status = + acpi_video_set_brightness; + sprintf(name, "acpi_video%d", count++); + device->data = acpi_video_data; + acpi_video_data->max_brightness = max_level; + acpi_video_device_lcd_get_level_current(device, &tmp); + acpi_video_data->brightness = (int)tmp; + device->backlight = backlight_device_register(name, + NULL, device, acpi_video_data); + kfree(name); + } return; } @@ -668,6 +736,8 @@ static int acpi_video_device_info_seq_sh seq_printf(seq, "LCD\n"); else if (dev->flags.tvout) seq_printf(seq, "TVOUT\n"); + else if (dev->flags.dvi) + seq_printf(seq, "DVI\n"); else seq_printf(seq, "UNKNOWN\n"); @@ -1242,6 +1312,16 @@ static int acpi_video_bus_remove_fs(stru -------------------------------------------------------------------------- */ /* device interface */ +static struct acpi_video_device_attrib* +acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) +{ + int count; + + for(count = 0; count < video->attached_count; count++) + if((video->attached_array[count].value.int_val & 0xffff) == device_id) + return &(video->attached_array[count].value.attrib); + return NULL; +} static int acpi_video_bus_get_one_device(struct acpi_device *device, @@ -1250,7 +1330,7 @@ acpi_video_bus_get_one_device(struct acp unsigned long device_id; int status; struct acpi_video_device *data; - + struct acpi_video_device_attrib* attribute; if (!device || !video) return -EINVAL; @@ -1271,20 +1351,30 @@ acpi_video_bus_get_one_device(struct acp data->video = video; data->dev = device; - switch (device_id & 0xffff) { - case 0x0100: - data->flags.crt = 1; - break; - case 0x0400: - data->flags.lcd = 1; - break; - case 0x0200: - data->flags.tvout = 1; - break; - default: + attribute = acpi_video_get_device_attr(video, device_id); + + if((attribute != NULL) && attribute->device_id_scheme) { + switch (attribute->display_type) { + case ACPI_VIDEO_DISPLAY_CRT: + data->flags.crt = 1; + break; + case ACPI_VIDEO_DISPLAY_TV: + data->flags.tvout = 1; + break; + case ACPI_VIDEO_DISPLAY_DVI: + data->flags.dvi = 1; + break; + case ACPI_VIDEO_DISPLAY_LCD: + data->flags.lcd = 1; + break; + default: + data->flags.unknown = 1; + break; + } + if(attribute->bios_can_detect) + data->flags.bios = 1; + } else data->flags.unknown = 1; - break; - } acpi_video_device_bind(video, data); acpi_video_device_find_cap(data); @@ -1588,7 +1678,10 @@ static int acpi_video_bus_put_one_device status = acpi_remove_notify_handler(device->dev->handle, ACPI_DEVICE_NOTIFY, acpi_video_device_notify); - + if (device->backlight){ + backlight_device_unregister(device->backlight); + kfree(device->data); + } return 0; } @@ -1792,39 +1885,6 @@ static int acpi_video_bus_remove(struct return 0; } -static int -acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver) -{ - acpi_handle h_dummy1; - acpi_handle h_dummy2; - acpi_handle h_dummy3; - - - if (!device || !driver) - return -EINVAL; - - /* Since there is no HID, CID for ACPI Video drivers, we have - * to check well known required nodes for each feature we support. - */ - - /* Does this device able to support video switching ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2))) - return 0; - - /* Does this device able to retrieve a video ROM ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1))) - return 0; - - /* Does this device able to configure which video head to be POSTed ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3))) - return 0; - - return -ENODEV; -} - static int __init acpi_video_init(void) { int result = 0; diff -puN /dev/null drivers/video/output.c --- /dev/null +++ a/drivers/video/output.c @@ -0,0 +1,129 @@ +/* + * output.c - Display Output Switch driver + * + * Copyright (C) 2006 Luming Yu + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + + +MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Luming Yu "); + +static ssize_t video_output_show_state(struct class_device *dev,char *buf) +{ + ssize_t ret_size = 0; + struct output_device *od = to_output_device(dev); + if (od->props) + ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); + return ret_size; +} + +static ssize_t video_output_store_state(struct class_device *dev, + const char *buf,size_t count) +{ + char *endp; + struct output_device *od = to_output_device(dev); + int request_state = simple_strtoul(buf,&endp,0); + size_t size = endp - buf; + + if (*endp && isspace(*endp)) + size++; + if (size != count) + return -EINVAL; + + if (od->props) { + od->request_state = request_state; + od->props->set_state(od); + } + return count; +} + +static void video_output_class_release(struct class_device *dev) +{ + struct output_device *od = to_output_device(dev); + kfree(od); +} + +static struct class_device_attribute video_output_attributes[] = { + __ATTR(state, 0644, video_output_show_state, video_output_store_state), + __ATTR_NULL, +}; + +static struct class video_output_class = { + .name = "video_output", + .release = video_output_class_release, + .class_dev_attrs = video_output_attributes, +}; + +struct output_device *video_output_register(const char *name, + struct device *dev, + void *devdata, + struct output_properties *op) +{ + struct output_device *new_dev; + int ret_code = 0; + + new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); + if (!new_dev) { + ret_code = -ENOMEM; + goto error_return; + } + new_dev->props = op; + new_dev->class_dev.class = &video_output_class; + new_dev->class_dev.dev = dev; + strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN); + class_set_devdata(&new_dev->class_dev,devdata); + ret_code = class_device_register(&new_dev->class_dev); + if (ret_code) { + kfree(new_dev); + goto error_return; + } + return new_dev; + +error_return: + return ERR_PTR(ret_code); +} +EXPORT_SYMBOL(video_output_register); + +void video_output_unregister(struct output_device *dev) +{ + if (!dev) + return; + class_device_unregister(&dev->class_dev); +} +EXPORT_SYMBOL(video_output_unregister); + +static void __exit video_output_class_exit(void) +{ + class_unregister(&video_output_class); +} + +static int __init video_output_class_init(void) +{ + return class_register(&video_output_class); +} + +postcore_initcall(video_output_class_init); +module_exit(video_output_class_exit); diff -puN include/acpi/acpi_bus.h~git-acpi include/acpi/acpi_bus.h --- a/include/acpi/acpi_bus.h~git-acpi +++ a/include/acpi/acpi_bus.h @@ -92,13 +92,12 @@ typedef int (*acpi_op_remove) (struct ac typedef int (*acpi_op_lock) (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, int state); -typedef int (*acpi_op_resume) (struct acpi_device * device, int state); +typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state); +typedef int (*acpi_op_resume) (struct acpi_device * device); typedef int (*acpi_op_scan) (struct acpi_device * device); typedef int (*acpi_op_bind) (struct acpi_device * device); typedef int (*acpi_op_unbind) (struct acpi_device * device); -typedef int (*acpi_op_match) (struct acpi_device * device, - struct acpi_driver * driver); +typedef int (*acpi_op_shutdown) (struct acpi_device * device); struct acpi_bus_ops { u32 acpi_op_add:1; @@ -111,7 +110,7 @@ struct acpi_bus_ops { u32 acpi_op_scan:1; u32 acpi_op_bind:1; u32 acpi_op_unbind:1; - u32 acpi_op_match:1; + u32 acpi_op_shutdown:1; u32 reserved:21; }; @@ -126,16 +125,16 @@ struct acpi_device_ops { acpi_op_scan scan; acpi_op_bind bind; acpi_op_unbind unbind; - acpi_op_match match; + acpi_op_shutdown shutdown; }; struct acpi_driver { - struct list_head node; char name[80]; char class[80]; - atomic_t references; char *ids; /* Supported Hardware IDs */ struct acpi_device_ops ops; + struct device_driver drv; + struct module *owner; }; /* @@ -185,7 +184,7 @@ struct acpi_device_dir { typedef char acpi_bus_id[5]; typedef unsigned long acpi_bus_address; -typedef char acpi_hardware_id[9]; +typedef char acpi_hardware_id[15]; typedef char acpi_unique_id[9]; typedef char acpi_device_name[40]; typedef char acpi_device_class[20]; @@ -296,11 +295,14 @@ struct acpi_device { struct acpi_device_ops ops; struct acpi_driver *driver; void *driver_data; - struct kobject kobj; struct device dev; + struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */ + enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ }; #define acpi_driver_data(d) ((d)->driver_data) +#define to_acpi_device(d) container_of(d, struct acpi_device, dev) +#define to_acpi_driver(d) container_of(d, struct acpi_driver, drv) /* * Events diff -puN include/acpi/acpi_drivers.h~git-acpi include/acpi/acpi_drivers.h --- a/include/acpi/acpi_drivers.h~git-acpi +++ a/include/acpi/acpi_drivers.h @@ -36,13 +36,14 @@ /* _HID definitions */ -#define ACPI_POWER_HID "ACPI_PWR" -#define ACPI_PROCESSOR_HID "ACPI_CPU" -#define ACPI_SYSTEM_HID "ACPI_SYS" -#define ACPI_THERMAL_HID "ACPI_THM" -#define ACPI_BUTTON_HID_POWERF "ACPI_FPB" -#define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB" - +#define ACPI_POWER_HID "power_resource" +#define ACPI_PROCESSOR_HID "processor" +#define ACPI_SYSTEM_HID "acpi_system" +#define ACPI_THERMAL_HID "thermal" +#define ACPI_BUTTON_HID_POWERF "button_power" +#define ACPI_BUTTON_HID_SLEEPF "button_sleep" +#define ACPI_VIDEO_HID "video" +#define ACPI_BAY_HID "bay" /* -------------------------------------------------------------------------- PCI -------------------------------------------------------------------------- */ diff -puN include/linux/acpi.h~git-acpi include/linux/acpi.h --- a/include/linux/acpi.h~git-acpi +++ a/include/linux/acpi.h @@ -47,6 +47,7 @@ enum acpi_irq_model_id { ACPI_IRQ_MODEL_PIC = 0, ACPI_IRQ_MODEL_IOAPIC, ACPI_IRQ_MODEL_IOSAPIC, + ACPI_IRQ_MODEL_PLATFORM, ACPI_IRQ_MODEL_COUNT }; @@ -389,7 +390,7 @@ typedef int (*acpi_table_handler) (unsig extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT]; -typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header, const unsigned long end); +typedef int (*acpi_table_entry_handler) (acpi_table_entry_header *header, const unsigned long end); char * __acpi_map_table (unsigned long phys_addr, unsigned long size); unsigned long acpi_find_rsdp (void); @@ -400,8 +401,8 @@ int acpi_numa_init (void); int acpi_table_init (void); int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header); -int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); -int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_table_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_table_entry_handler handler, unsigned int max_entries); int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); void acpi_table_print_madt_entry (acpi_table_entry_header *madt); diff -puN /dev/null include/linux/video_output.h --- /dev/null +++ a/include/linux/video_output.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (C) 2006 Luming Yu + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#ifndef _LINUX_VIDEO_OUTPUT_H +#define _LINUX_VIDEO_OUTPUT_H +#include +struct output_device; +struct output_properties { + int (*set_state)(struct output_device *); + int (*get_status)(struct output_device *); +}; +struct output_device { + int request_state; + struct output_properties *props; + struct class_device class_dev; +}; +#define to_output_device(obj) container_of(obj, struct output_device, class_dev) +struct output_device *video_output_register(const char *name, + struct device *dev, + void *devdata, + struct output_properties *op); +void video_output_unregister(struct output_device *dev); +#endif _