GIT ff25fd7858e59949bbaeaea73d98dc3b8e93aafb git+ssh://master.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git#test commit 39c31576c2610337ec04f01939dfab72847750ed Author: Bob Moore Date: Wed May 2 15:51:37 2007 -0400 ACPICA: Clear reserved fields for incoming ACPI 1.0 FADTs Fixed a problem with the internal FADT conversion where ACPI 1.0 FADTs that contained invalid non-zero values in reserved fields could cause later failures because these fields have meaning in later revisions of the FADT. For incoming ACPI 1.0 FADTs, these fields are now always zeroed. (Preferred_PM_Profile, PSTATE_CNT, CST_CNT, IAPC_BOOT_FLAGS.) Signed-off-by: Bob Moore Signed-off-by: Len Brown commit 3fb364812c61294ecec0c09d546f3c35be3353a8 Author: Bob Moore Date: Tue Apr 3 20:00:29 2007 -0400 ACPICA: Fixed possible corruption of global GPE list Fixed a problem in acpi_ev_delete_gpe_xrupt where the global interrupt list could be corrupted if the interrupt being removed was at the head of the list. Reported by Linn Crosetto. Signed-off-by: Bob Moore Signed-off-by: Len Brown commit 22455d0ecdf2b178a081b05de3dad1801baf0957 Author: Bob Moore Date: Tue Apr 3 19:59:37 2007 -0400 ACPICA: Support for external package objects as method arguments Implemented support to allow Package objects to be passed as method arguments to the acpi_evaluate_object interface. Previously, this would return an AE_NOT_IMPLEMENTED exception. Signed-off-by: Bob Moore Signed-off-by: Len Brown commit 7dcb691fa4224c3c74095ffabcc7d992e69221f6 Author: Bob Moore Date: Tue Mar 27 20:25:46 2007 -0400 ACPICA: Changes for Cygwin compatibility Allow generation of ACPICA apps on Cygwin. Signed-off-by: Bob Moore Signed-off-by: Len Brown commit 9da86eb6ffdbc92f2d977663d46d361d18fd9e68 Author: Bob Moore Date: Mon Mar 26 22:10:34 2007 -0400 ACPICA: Update _OSI string list Latest update for the Windows strings, with comments. Removed unused strings. Signed-off-by: Bob Moore Signed-off-by: Len Brown commit 78490d82129f7331d1366737c8704c1c053221a3 Author: Alexey Starikovskiy Date: Fri May 11 13:18:55 2007 -0400 ACPI: battery: syntax cleanup In response to review comments from Andrew Morton Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 1f9767df1346c9ce09d6e51b9f34b851e3d94fad Author: Kristen Carlson Accardi Date: Wed May 9 15:55:53 2007 -0700 ACPI: bay: unsuppress uevents Since platform devices seem to get uevents suppressed by default, manually unsuppress for the bay device since we want to be able to send uevents. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit 79a8f70b4b9127eacfc91dd1436c4a7be05e62ab Author: Kristen Carlson Accardi Date: Wed May 9 15:10:22 2007 -0700 ACPI: dock: send envp with uevent Send an env along with our KOBJ_CHANGE uevent so that user space has the option of checking for that to see if a dock or undock has occurred. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit 9ef2a9a9f08722998540ed2ff38bccd0c54344c8 Author: Kristen Carlson Accardi Date: Wed May 9 15:09:12 2007 -0700 ACPI: dock: unsuppress uevents Platform devices may not send uevents by default - override the setting so that we can send uevents on dock/undock. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit a0cd35fdca0bb711854edeaf016cec6cdf82eeca Author: Kristen Carlson Accardi Date: Wed May 9 15:08:15 2007 -0700 ACPI: dock: add immediate_undock option Allow the driver to be loaded with an option that will allow userspace to control whether the laptop is ejected immediately when the user presses the button, or only when the syfs undock file is written. if immediate_undock == 1, then when the user presses the undock button, the laptop will send an event to userspace to notify userspace of the undock, but then immediately undock without waiting for userspace. This is the current behavior, and I set this to be the default. if immediate_undock == 0, then when the user presses the undock button, the laptop will send an event to userspace and do nothing. User space can query the "flags" sysfs entry to determine if an undock request has been made by the user (if bit 1 is set). User space will then need to write the undock sysfs entry to complete the undocking process. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit 0f6f2804563eee64f0fc7cbcb009b98b6f332af6 Author: Kristen Carlson Accardi Date: Wed May 9 15:07:04 2007 -0700 ACPI: dock: use dynamically allocated platform device Get rid of no release function warnings by switching to dynamically allocating the platform_device and using the platform device release routine in the base driver. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit 22fe4c2114e29477ca6738729c074ee8f60d3b73 Author: Chuck Ebbert Date: Wed May 9 15:05:48 2007 -0700 ACPI: dock: fix opps after dock driver fails to initialize The driver tests the dock_station pointer for nonnull to check whether it has initialized properly. But in some cases dock_station will be non-null after being freed when driver init fails. Fix by zeroing the pointer after freeing. Signed-off-by: Chuck Ebbert Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit 38ff4ffc039ba5a5878f2dcbb03d87c3a1f02f1b Author: Kristen Carlson Accardi Date: Wed May 9 15:04:24 2007 -0700 ACPI: dock: cleanup the uid patch Make uid sysfs file error path free memory, and cleanup sysfs file when removing driver. Also fix CodingStyle violations. Signed-off-by: Kristen Carlson Accardi Cc: Illya A. Volynets-Evenbakh Signed-off-by: Len Brown commit 23b0f015bf2c050b8b5399430ca64e1b3398cf76 Author: Luming Yu Date: Wed May 9 21:07:05 2007 +0800 ACPI: video: output switch sysfs support Requires CONFIG_VIDEO_OUTPUT_CONTROL and CONFIG_ACPI_VIDEO. After loading output.ko and video.ko, you would have /sys/class/video_output and several device acpi_videoNum there. For example, I got acpi_video0, acpi_video1,acpi_video2,and acpi_video3 under /sys/class/video_output on my T40. I can query the status of output device0 by running " cat /sys/class/video_output/acpi_video0 " The return value is defined in ACPI SPEC B.5.5 _DCS(Return the Status of Output Device). Also you can turn off video1 and turn on video0 by " echo 0 > acpi_video1; echo 0x80000000 > acpi_video0". Please reference ACPI SPEC B.5.7 _DSS for the parameter definition. Please note that it may or may NOT works purely depending on if your vendor providing correct ACPI video extension support in bios. the driver output.ko and video.ko just works like a interface to invoke BIOS. Signed-off-by: Luming Yu Signed-off-by: Len Brown commit 6eedeef73e7fff32eb5fa25178c3c77b1db0ec0f Author: Vladimir Lebedev Date: Sat Apr 21 22:41:48 2007 -0400 process reading battery status hangs http://bugzilla.kernel.org/show_bug.cgi?id=8351 Signed-off-by: Vladimir Lebedev Signed-off-by: Len Brown commit 9ea7d57576f40c6af03c8c9fa7a069f2222b498b Author: Vladimir Lebedev Date: Tue Feb 20 15:48:06 2007 +0300 ACPI: battery: Lindent Signed-off-by: Vladimir Lebedev Signed-off-by: Len Brown commit b6ce4083ed8e2a01a3a59301eabe0fc1e68a8a84 Author: Vladimir Lebedev Date: Tue Feb 20 15:48:06 2007 +0300 ACPI: Cache battery status instead of re-evaluating AML /proc exports _BST in a single file, and _BST is re-evaulated whenever that file is read. Sometimes user-space reads this file frequently, and on some systems _BST takes a long time to evaluate due to a slow EC. Further, when we move to sysfs, the values returned from _BST will be in multiple files, and evaluating _BST for each file read would make matters worse. Here code is added to support caching the results of _BST. A new module parameter "update_time" tells how many seconds the cached _BST should be used before it is re-evaluated. Currently, update_time defaults to 0, and so the existing behaviour of re-evaluating on each read retained. Signed-off-by: Vladimir Lebedev Signed-off-by: Len Brown commit a1f0eff21edac1bd87e397f56c4258b9611b5a50 Author: Vladimir Lebedev Date: Tue Feb 20 15:48:06 2007 +0300 ACPI: battery: make internal names consistent with battery "state" Cleanup -- No functional changes. Battery state is currently exported in a proc "state" file. Update associated #defines and routines to be consistent. Signed-off-by: Vladimir Lebedev Signed-off-by: Len Brown drivers/acpi/Kconfig | 2 drivers/acpi/battery.c | 673 ++++++++++++++++++++++++------------- drivers/acpi/bay.c | 5 drivers/acpi/dock.c | 119 +++++-- drivers/acpi/events/evgpeblk.c | 4 drivers/acpi/tables/tbfadt.c | 44 +- drivers/acpi/utilities/utcopy.c | 120 +++---- drivers/acpi/utilities/uteval.c | 17 - drivers/acpi/utilities/utobject.c | 42 ++ drivers/acpi/video.c | 40 ++ drivers/video/Kconfig | 7 drivers/video/Makefile | 3 include/acpi/acutils.h | 2 include/acpi/platform/acenv.h | 2 include/acpi/platform/aclinux.h | 3 15 files changed, 722 insertions(+), 361 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 139f41f..eb4855f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -124,7 +124,7 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" - depends on X86 && BACKLIGHT_CLASS_DEVICE + depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index e64c76c..cad932d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -43,21 +43,30 @@ #define ACPI_BATTERY_COMPONENT 0x000400 #define ACPI_BATTERY_CLASS "battery" #define ACPI_BATTERY_HID "PNP0C0A" #define ACPI_BATTERY_DEVICE_NAME "Battery" -#define ACPI_BATTERY_FILE_INFO "info" -#define ACPI_BATTERY_FILE_STATUS "state" -#define ACPI_BATTERY_FILE_ALARM "alarm" #define ACPI_BATTERY_NOTIFY_STATUS 0x80 #define ACPI_BATTERY_NOTIFY_INFO 0x81 #define ACPI_BATTERY_UNITS_WATTS "mW" #define ACPI_BATTERY_UNITS_AMPS "mA" #define _COMPONENT ACPI_BATTERY_COMPONENT + +#define ACPI_BATTERY_UPDATE_TIME 0 + +#define ACPI_BATTERY_NONE_UPDATE 0 +#define ACPI_BATTERY_EASY_UPDATE 1 +#define ACPI_BATTERY_INIT_UPDATE 2 + ACPI_MODULE_NAME("battery"); MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); +static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME; + +/* 0 - every time, > 0 - by update_time */ +module_param(update_time, uint, 0644); + extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); @@ -76,7 +85,7 @@ static struct acpi_driver acpi_battery_d }, }; -struct acpi_battery_status { +struct acpi_battery_state { acpi_integer state; acpi_integer present_rate; acpi_integer remaining_capacity; @@ -99,33 +108,111 @@ struct acpi_battery_info { acpi_string oem_info; }; -struct acpi_battery_flags { - u8 present:1; /* Bay occupied? */ - u8 power_unit:1; /* 0=watts, 1=apms */ - u8 alarm:1; /* _BTP present? */ - u8 reserved:5; +enum acpi_battery_files{ + ACPI_BATTERY_INFO = 0, + ACPI_BATTERY_STATE, + ACPI_BATTERY_ALARM, + ACPI_BATTERY_NUMFILES, }; -struct acpi_battery_trips { - unsigned long warning; - unsigned long low; +struct acpi_battery_flags { + u8 battery_present_prev; + u8 alarm_present; + u8 init_update; + u8 update[ACPI_BATTERY_NUMFILES]; + u8 power_unit; }; struct acpi_battery { - struct acpi_device * device; + struct mutex mutex; + struct acpi_device *device; struct acpi_battery_flags flags; - struct acpi_battery_trips trips; + struct acpi_buffer bif_data; + struct acpi_buffer bst_data; unsigned long alarm; - struct acpi_battery_info *info; + unsigned long update_time[ACPI_BATTERY_NUMFILES]; }; +inline int acpi_battery_present(struct acpi_battery *battery) +{ + return battery->device->status.battery_present; +} +inline char *acpi_battery_power_units(struct acpi_battery *battery) +{ + if (battery->flags.power_unit) + return ACPI_BATTERY_UNITS_AMPS; + else + return ACPI_BATTERY_UNITS_WATTS; +} + +inline acpi_handle acpi_battery_handle(struct acpi_battery *battery) +{ + return battery->device->handle; +} + /* -------------------------------------------------------------------------- Battery Management -------------------------------------------------------------------------- */ -static int -acpi_battery_get_info(struct acpi_battery *battery, - struct acpi_battery_info **bif) +static void acpi_battery_check_result(struct acpi_battery *battery, int result) +{ + if (!battery) + return; + + if (result) { + battery->flags.init_update = 1; + } +} + +static int acpi_battery_extract_package(struct acpi_battery *battery, + union acpi_object *package, + struct acpi_buffer *format, + struct acpi_buffer *data, + char *package_name) +{ + acpi_status status = AE_OK; + struct acpi_buffer data_null = { 0, NULL }; + + status = acpi_extract_package(package, format, &data_null); + if (status != AE_BUFFER_OVERFLOW) { + ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s", + package_name)); + return -ENODEV; + } + + if (data_null.length != data->length) { + kfree(data->pointer); + data->pointer = kzalloc(data_null.length, GFP_KERNEL); + if (!data->pointer) { + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()")); + return -ENOMEM; + } + data->length = data_null.length; + } + + status = acpi_extract_package(package, format, data); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Extracting %s", + package_name)); + return -ENODEV; + } + + return 0; +} + +static int acpi_battery_get_status(struct acpi_battery *battery) +{ + int result = 0; + + result = acpi_bus_get_status(battery->device); + if (result) { + ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); + return -ENODEV; + } + return result; +} + +static int acpi_battery_get_info(struct acpi_battery *battery) { int result = 0; acpi_status status = 0; @@ -133,16 +220,20 @@ acpi_battery_get_info(struct acpi_batter struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), ACPI_BATTERY_FORMAT_BIF }; - struct acpi_buffer data = { 0, NULL }; union acpi_object *package = NULL; + struct acpi_buffer *data = NULL; + struct acpi_battery_info *bif = NULL; + battery->update_time[ACPI_BATTERY_INFO] = get_seconds(); - if (!battery || !bif) - return -EINVAL; + if (!acpi_battery_present(battery)) + return 0; - /* Evalute _BIF */ + /* Evaluate _BIF */ - status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer); + status = + acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, + &buffer); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); return -ENODEV; @@ -150,41 +241,29 @@ acpi_battery_get_info(struct acpi_batter package = buffer.pointer; - /* Extract Package Data */ - - status = acpi_extract_package(package, &format, &data); - if (status != AE_BUFFER_OVERFLOW) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF")); - result = -ENODEV; - goto end; - } + data = &battery->bif_data; - data.pointer = kzalloc(data.length, GFP_KERNEL); - if (!data.pointer) { - result = -ENOMEM; - goto end; - } + /* Extract Package Data */ - status = acpi_extract_package(package, &format, &data); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF")); - kfree(data.pointer); - result = -ENODEV; + result = + acpi_battery_extract_package(battery, package, &format, data, + "_BIF"); + if (result) goto end; - } end: + kfree(buffer.pointer); - if (!result) - (*bif) = data.pointer; + if (!result) { + bif = data->pointer; + battery->flags.power_unit = bif->power_unit; + } return result; } -static int -acpi_battery_get_status(struct acpi_battery *battery, - struct acpi_battery_status **bst) +static int acpi_battery_get_state(struct acpi_battery *battery) { int result = 0; acpi_status status = 0; @@ -192,16 +271,19 @@ acpi_battery_get_status(struct acpi_batt struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), ACPI_BATTERY_FORMAT_BST }; - struct acpi_buffer data = { 0, NULL }; union acpi_object *package = NULL; + struct acpi_buffer *data = NULL; + battery->update_time[ACPI_BATTERY_STATE] = get_seconds(); - if (!battery || !bst) - return -EINVAL; + if (!acpi_battery_present(battery)) + return 0; - /* Evalute _BST */ + /* Evaluate _BST */ - status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer); + status = + acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, + &buffer); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); return -ENODEV; @@ -209,55 +291,49 @@ acpi_battery_get_status(struct acpi_batt package = buffer.pointer; - /* Extract Package Data */ - - status = acpi_extract_package(package, &format, &data); - if (status != AE_BUFFER_OVERFLOW) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST")); - result = -ENODEV; - goto end; - } + data = &battery->bst_data; - data.pointer = kzalloc(data.length, GFP_KERNEL); - if (!data.pointer) { - result = -ENOMEM; - goto end; - } + /* Extract Package Data */ - status = acpi_extract_package(package, &format, &data); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST")); - kfree(data.pointer); - result = -ENODEV; + result = + acpi_battery_extract_package(battery, package, &format, data, + "_BST"); + if (result) goto end; - } end: kfree(buffer.pointer); - if (!result) - (*bst) = data.pointer; - return result; } -static int -acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) +static int acpi_battery_get_alarm(struct acpi_battery *battery) +{ + battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); + + return 0; +} + +static int acpi_battery_set_alarm(struct acpi_battery *battery, + unsigned long alarm) { acpi_status status = 0; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list arg_list = { 1, &arg0 }; + battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); - if (!battery) - return -EINVAL; + if (!acpi_battery_present(battery)) + return -ENODEV; - if (!battery->flags.alarm) + if (!battery->flags.alarm_present) return -ENODEV; arg0.integer.value = alarm; - status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL); + status = + acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", + &arg_list, NULL); if (ACPI_FAILURE(status)) return -ENODEV; @@ -268,65 +344,114 @@ acpi_battery_set_alarm(struct acpi_batte return 0; } -static int acpi_battery_check(struct acpi_battery *battery) +static int acpi_battery_init_alarm(struct acpi_battery *battery) { int result = 0; acpi_status status = AE_OK; acpi_handle handle = NULL; - struct acpi_device *device = NULL; - struct acpi_battery_info *bif = NULL; + struct acpi_battery_info *bif = battery->bif_data.pointer; + unsigned long alarm = battery->alarm; + /* See if alarms are supported, and if so, set default */ - if (!battery) - return -EINVAL; - - device = battery->device; + status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); + if (ACPI_SUCCESS(status)) { + battery->flags.alarm_present = 1; + if (!alarm && bif) { + alarm = bif->design_capacity_warning; + } + result = acpi_battery_set_alarm(battery, alarm); + if (result) + goto end; + } else { + battery->flags.alarm_present = 0; + } - result = acpi_bus_get_status(device); - if (result) - return result; + end: - /* Insertion? */ + return result; +} - if (!battery->flags.present && device->status.battery_present) { +static int acpi_battery_init_update(struct acpi_battery *battery) +{ + int result = 0; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n")); + result = acpi_battery_get_status(battery); + if (result) + return result; - /* Evalute _BIF to get certain static information */ + battery->flags.battery_present_prev = acpi_battery_present(battery); - result = acpi_battery_get_info(battery, &bif); + if (acpi_battery_present(battery)) { + result = acpi_battery_get_info(battery); + if (result) + return result; + result = acpi_battery_get_state(battery); if (result) return result; - battery->flags.power_unit = bif->power_unit; - battery->trips.warning = bif->design_capacity_warning; - battery->trips.low = bif->design_capacity_low; - kfree(bif); + acpi_battery_init_alarm(battery); + } + + return result; +} - /* See if alarms are supported, and if so, set default */ +static int acpi_battery_update(struct acpi_battery *battery, + int update, int *update_result_ptr) +{ + int result = 0; + int update_result = ACPI_BATTERY_NONE_UPDATE; + + if (!acpi_battery_present(battery)) { + update = 1; + } - status = acpi_get_handle(battery->device->handle, "_BTP", &handle); - if (ACPI_SUCCESS(status)) { - battery->flags.alarm = 1; - acpi_battery_set_alarm(battery, battery->trips.warning); + if (battery->flags.init_update) { + result = acpi_battery_init_update(battery); + if (result) + goto end; + update_result = ACPI_BATTERY_INIT_UPDATE; + } else if (update) { + result = acpi_battery_get_status(battery); + if (result) + goto end; + if ((!battery->flags.battery_present_prev & acpi_battery_present(battery)) + || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) { + result = acpi_battery_init_update(battery); + if (result) + goto end; + update_result = ACPI_BATTERY_INIT_UPDATE; + } else { + update_result = ACPI_BATTERY_EASY_UPDATE; } } - /* Removal? */ + end: - else if (battery->flags.present && !device->status.battery_present) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n")); - } + battery->flags.init_update = (result != 0); - battery->flags.present = device->status.battery_present; + *update_result_ptr = update_result; return result; } -static void acpi_battery_check_present(struct acpi_battery *battery) +static void acpi_battery_notify_update(struct acpi_battery *battery) { - if (!battery->flags.present) { - acpi_battery_check(battery); + acpi_battery_get_status(battery); + + if (battery->flags.init_update) { + return; + } + + if ((!battery->flags.battery_present_prev & + acpi_battery_present(battery)) || + (battery->flags.battery_present_prev & + !acpi_battery_present(battery))) { + battery->flags.init_update = 1; + } else { + battery->flags.update[ACPI_BATTERY_INFO] = 1; + battery->flags.update[ACPI_BATTERY_STATE] = 1; + battery->flags.update[ACPI_BATTERY_ALARM] = 1; } } @@ -335,37 +460,33 @@ static void acpi_battery_check_present(s -------------------------------------------------------------------------- */ static struct proc_dir_entry *acpi_battery_dir; -static int acpi_battery_read_info(struct seq_file *seq, void *offset) + +static int acpi_battery_print_info(struct seq_file *seq, int result) { - int result = 0; struct acpi_battery *battery = seq->private; struct acpi_battery_info *bif = NULL; char *units = "?"; - - if (!battery) + if (result) goto end; - acpi_battery_check_present(battery); - - if (battery->flags.present) + if (acpi_battery_present(battery)) seq_printf(seq, "present: yes\n"); else { seq_printf(seq, "present: no\n"); goto end; } - /* Battery Info (_BIF) */ - - result = acpi_battery_get_info(battery, &bif); - if (result || !bif) { - seq_printf(seq, "ERROR: Unable to read battery information\n"); + bif = battery->bif_data.pointer; + if (!bif) { + ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL")); + result = -ENODEV; goto end; } - units = - bif-> - power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; + /* Battery Units */ + + units = acpi_battery_power_units(battery); if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design capacity: unknown\n"); @@ -396,7 +517,6 @@ static int acpi_battery_read_info(struct else seq_printf(seq, "design voltage: %d mV\n", (u32) bif->design_voltage); - seq_printf(seq, "design capacity warning: %d %sh\n", (u32) bif->design_capacity_warning, units); seq_printf(seq, "design capacity low: %d %sh\n", @@ -411,50 +531,40 @@ static int acpi_battery_read_info(struct seq_printf(seq, "OEM info: %s\n", bif->oem_info); end: - kfree(bif); - return 0; -} + if (result) + seq_printf(seq, "ERROR: Unable to read battery info\n"); -static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_battery_read_info, PDE(inode)->data); + return result; } -static int acpi_battery_read_state(struct seq_file *seq, void *offset) +static int acpi_battery_print_state(struct seq_file *seq, int result) { - int result = 0; struct acpi_battery *battery = seq->private; - struct acpi_battery_status *bst = NULL; + struct acpi_battery_state *bst = NULL; char *units = "?"; - - if (!battery) + if (result) goto end; - acpi_battery_check_present(battery); - - if (battery->flags.present) + if (acpi_battery_present(battery)) seq_printf(seq, "present: yes\n"); else { seq_printf(seq, "present: no\n"); goto end; } - /* Battery Units */ - - units = - battery->flags. - power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; - - /* Battery Status (_BST) */ - - result = acpi_battery_get_status(battery, &bst); - if (result || !bst) { - seq_printf(seq, "ERROR: Unable to read battery status\n"); + bst = battery->bst_data.pointer; + if (!bst) { + ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL")); + result = -ENODEV; goto end; } + /* Battery Units */ + + units = acpi_battery_power_units(battery); + if (!(bst->state & 0x04)) seq_printf(seq, "capacity state: ok\n"); else @@ -490,48 +600,43 @@ static int acpi_battery_read_state(struc (u32) bst->present_voltage); end: - kfree(bst); - return 0; -} + if (result) { + seq_printf(seq, "ERROR: Unable to read battery state\n"); + } -static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_battery_read_state, PDE(inode)->data); + return result; } -static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) +static int acpi_battery_print_alarm(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; char *units = "?"; - - if (!battery) + if (result) goto end; - acpi_battery_check_present(battery); - - if (!battery->flags.present) { + if (!acpi_battery_present(battery)) { seq_printf(seq, "present: no\n"); goto end; } /* Battery Units */ - units = - battery->flags. - power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; - - /* Battery Alarm */ + units = acpi_battery_power_units(battery); seq_printf(seq, "alarm: "); if (!battery->alarm) seq_printf(seq, "unsupported\n"); else - seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units); + seq_printf(seq, "%lu %sh\n", battery->alarm, units); end: - return 0; + + if (result) + seq_printf(seq, "ERROR: Unable to read battery alarm\n"); + + return result; } static ssize_t @@ -543,27 +648,113 @@ acpi_battery_write_alarm(struct file *fi char alarm_string[12] = { '\0' }; struct seq_file *m = file->private_data; struct acpi_battery *battery = m->private; - + int update_result = ACPI_BATTERY_NONE_UPDATE; if (!battery || (count > sizeof(alarm_string) - 1)) return -EINVAL; - acpi_battery_check_present(battery); + mutex_lock(&battery->mutex); - if (!battery->flags.present) - return -ENODEV; + result = acpi_battery_update(battery, 1, &update_result); + if (result) { + result = -ENODEV; + goto end; + } + + if (!acpi_battery_present(battery)) { + result = -ENODEV; + goto end; + } - if (copy_from_user(alarm_string, buffer, count)) - return -EFAULT; + if (copy_from_user(alarm_string, buffer, count)) { + result = -EFAULT; + goto end; + } alarm_string[count] = '\0'; result = acpi_battery_set_alarm(battery, simple_strtoul(alarm_string, NULL, 0)); if (result) - return result; + goto end; + + end: - return count; + acpi_battery_check_result(battery, result); + + if (!result) + result = count; + + mutex_unlock(&battery->mutex); + + return result; +} + +typedef int(*print_func)(struct seq_file *seq, int result); +typedef int(*get_func)(struct acpi_battery *battery); + +static struct acpi_read_mux { + print_func print; + get_func get; +} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = { + {.get = acpi_battery_get_info, .print = acpi_battery_print_info}, + {.get = acpi_battery_get_state, .print = acpi_battery_print_state}, + {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm}, +}; + +static int acpi_battery_read(int fid, struct seq_file *seq) +{ + struct acpi_battery *battery = seq->private; + int result = 0; + int update_result = ACPI_BATTERY_NONE_UPDATE; + int update = 0; + + mutex_lock(&battery->mutex); + + update = (get_seconds() - battery->update_time[fid] >= update_time); + update = (update | battery->flags.update[fid]); + + result = acpi_battery_update(battery, update, &update_result); + if (result) + goto end; + + if (update_result == ACPI_BATTERY_EASY_UPDATE) { + result = acpi_read_funcs[fid].get(battery); + if (result) + goto end; + } + + end: + result = acpi_read_funcs[fid].print(seq, result); + acpi_battery_check_result(battery, result); + battery->flags.update[fid] = result; + mutex_unlock(&battery->mutex); + return result; +} + +static int acpi_battery_read_info(struct seq_file *seq, void *offset) +{ + return acpi_battery_read(ACPI_BATTERY_INFO, seq); +} + +static int acpi_battery_read_state(struct seq_file *seq, void *offset) +{ + return acpi_battery_read(ACPI_BATTERY_STATE, seq); +} + +static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) +{ + return acpi_battery_read(ACPI_BATTERY_ALARM, seq); +} + +static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, acpi_battery_read_info, PDE(inode)->data); +} + +static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, acpi_battery_read_state, PDE(inode)->data); } static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) @@ -571,35 +762,51 @@ static int acpi_battery_alarm_open_fs(st return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); } -static const struct file_operations acpi_battery_info_ops = { +static struct battery_file { + struct file_operations ops; + mode_t mode; + char *name; +} acpi_battery_file[] = { + { + .name = "info", + .mode = S_IRUGO, + .ops = { .open = acpi_battery_info_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE, -}; - -static const struct file_operations acpi_battery_state_ops = { + }, + }, + { + .name = "state", + .mode = S_IRUGO, + .ops = { .open = acpi_battery_state_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE, -}; - -static const struct file_operations acpi_battery_alarm_ops = { + }, + }, + { + .name = "alarm", + .mode = S_IFREG | S_IRUGO | S_IWUSR, + .ops = { .open = acpi_battery_alarm_open_fs, .read = seq_read, .write = acpi_battery_write_alarm, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE, + }, + }, }; static int acpi_battery_add_fs(struct acpi_device *device) { struct proc_dir_entry *entry = NULL; - + int i; if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), @@ -609,38 +816,16 @@ static int acpi_battery_add_fs(struct ac acpi_device_dir(device)->owner = THIS_MODULE; } - /* 'info' [R] */ - entry = create_proc_entry(ACPI_BATTERY_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); - if (!entry) - return -ENODEV; - else { - entry->proc_fops = &acpi_battery_info_ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - - /* 'status' [R] */ - entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS, - S_IRUGO, acpi_device_dir(device)); - if (!entry) - return -ENODEV; - else { - entry->proc_fops = &acpi_battery_state_ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - - /* 'alarm' [R/W] */ - entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); - if (!entry) - return -ENODEV; - else { - entry->proc_fops = &acpi_battery_alarm_ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; + for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { + entry = create_proc_entry(acpi_battery_file[i].name, + acpi_battery_file[i].mode, acpi_device_dir(device)); + if (!entry) + return -ENODEV; + else { + entry->proc_fops = &acpi_battery_file[i].ops; + entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; + } } return 0; @@ -648,15 +833,12 @@ static int acpi_battery_add_fs(struct ac static int acpi_battery_remove_fs(struct acpi_device *device) { - + int i; if (acpi_device_dir(device)) { - remove_proc_entry(ACPI_BATTERY_FILE_ALARM, + for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { + remove_proc_entry(acpi_battery_file[i].name, acpi_device_dir(device)); - remove_proc_entry(ACPI_BATTERY_FILE_STATUS, - acpi_device_dir(device)); - remove_proc_entry(ACPI_BATTERY_FILE_INFO, - acpi_device_dir(device)); - + } remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); acpi_device_dir(device) = NULL; } @@ -673,7 +855,6 @@ static void acpi_battery_notify(acpi_han struct acpi_battery *battery = data; struct acpi_device *device = NULL; - if (!battery) return; @@ -684,8 +865,10 @@ static void acpi_battery_notify(acpi_han case ACPI_BATTERY_NOTIFY_INFO: case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - acpi_battery_check(battery); - acpi_bus_generate_event(device, event, battery->flags.present); + device = battery->device; + acpi_battery_notify_update(battery); + acpi_bus_generate_event(device, event, + acpi_battery_present(battery)); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -702,7 +885,6 @@ static int acpi_battery_add(struct acpi_ acpi_status status = 0; struct acpi_battery *battery = NULL; - if (!device) return -EINVAL; @@ -710,15 +892,21 @@ static int acpi_battery_add(struct acpi_ if (!battery) return -ENOMEM; + mutex_init(&battery->mutex); + + mutex_lock(&battery->mutex); + battery->device = device; strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); acpi_driver_data(device) = battery; - result = acpi_battery_check(battery); + result = acpi_battery_get_status(battery); if (result) goto end; + battery->flags.init_update = 1; + result = acpi_battery_add_fs(device); if (result) goto end; @@ -727,6 +915,7 @@ static int acpi_battery_add(struct acpi_ ACPI_ALL_NOTIFY, acpi_battery_notify, battery); if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler")); result = -ENODEV; goto end; } @@ -736,11 +925,14 @@ static int acpi_battery_add(struct acpi_ device->status.battery_present ? "present" : "absent"); end: + if (result) { acpi_battery_remove_fs(device); kfree(battery); } + mutex_unlock(&battery->mutex); + return result; } @@ -749,18 +941,27 @@ static int acpi_battery_remove(struct ac acpi_status status = 0; struct acpi_battery *battery = NULL; - if (!device || !acpi_driver_data(device)) return -EINVAL; battery = acpi_driver_data(device); + mutex_lock(&battery->mutex); + status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify); acpi_battery_remove_fs(device); + kfree(battery->bif_data.pointer); + + kfree(battery->bst_data.pointer); + + mutex_unlock(&battery->mutex); + + mutex_destroy(&battery->mutex); + kfree(battery); return 0; @@ -775,7 +976,10 @@ static int acpi_battery_resume(struct ac return -EINVAL; battery = device->driver_data; - return acpi_battery_check(battery); + + battery->flags.init_update = 1; + + return 0; } static int __init acpi_battery_init(void) @@ -800,7 +1004,6 @@ static int __init acpi_battery_init(void static void __exit acpi_battery_exit(void) { - acpi_bus_unregister_driver(&acpi_battery_driver); acpi_unlock_battery_dir(acpi_battery_dir); diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index fb3f31b..00d3f3f 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -288,6 +288,11 @@ static int bay_add(acpi_handle handle, i new_bay->pdev = pdev; platform_set_drvdata(pdev, new_bay); + /* + * we want the bay driver to be able to send uevents + */ + pdev->dev.uevent_suppress = 0; + if (acpi_bay_add_fs(new_bay)) { platform_device_unregister(new_bay->pdev); goto bay_add_err; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 4546bf8..dc3df93 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -40,8 +40,15 @@ MODULE_AUTHOR("Kristen Carlson Accardi") MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); MODULE_LICENSE("GPL"); +static int immediate_undock = 1; +module_param(immediate_undock, bool, 0644); +MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " + "undock immediately when the undock button is pressed, 0 will cause" + " the driver to wait for userspace to write the undock sysfs file " + " before undocking"); + static struct atomic_notifier_head dock_notifier_list; -static struct platform_device dock_device; +static struct platform_device *dock_device; static char dock_device_name[] = "dock"; struct dock_station { @@ -63,6 +70,7 @@ struct dock_dependent_device { }; #define DOCK_DOCKING 0x00000001 +#define DOCK_UNDOCKING 0x00000002 #define DOCK_EVENT 3 #define UNDOCK_EVENT 2 @@ -327,12 +335,20 @@ static void hotplug_dock_devices(struct static void dock_event(struct dock_station *ds, u32 event, int num) { - struct device *dev = &dock_device.dev; + struct device *dev = &dock_device->dev; + char event_string[7]; + char *envp[] = { event_string, NULL }; + + if (num == UNDOCK_EVENT) + sprintf(event_string, "UNDOCK"); + else + sprintf(event_string, "DOCK"); + /* * Indicate that the status of the dock station has * changed. */ - kobject_uevent(&dev->kobj, KOBJ_CHANGE); + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } /** @@ -420,6 +436,16 @@ static inline void complete_dock(struct ds->last_dock_time = jiffies; } +static inline void begin_undock(struct dock_station *ds) +{ + ds->flags |= DOCK_UNDOCKING; +} + +static inline void complete_undock(struct dock_station *ds) +{ + ds->flags &= ~(DOCK_UNDOCKING); +} + /** * dock_in_progress - see if we are in the middle of handling a dock event * @ds: the dock station @@ -550,7 +576,7 @@ static int handle_eject_request(struct d printk(KERN_ERR PREFIX "Unable to undock!\n"); return -EBUSY; } - + complete_undock(ds); return 0; } @@ -594,7 +620,11 @@ static void dock_notify(acpi_handle hand * to the driver who wish to hotplug. */ case ACPI_NOTIFY_EJECT_REQUEST: - handle_eject_request(ds, event); + begin_undock(ds); + if (immediate_undock) + handle_eject_request(ds, event); + else + dock_event(ds, event, UNDOCK_EVENT); break; default: printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); @@ -653,6 +683,17 @@ static ssize_t show_docked(struct device DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); /* + * show_flags - read method for flags file in sysfs + */ +static ssize_t show_flags(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); + +} +DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); + +/* * write_undock - write method for "undock" file in sysfs */ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, @@ -675,16 +716,15 @@ static ssize_t show_dock_uid(struct devi struct device_attribute *attr, char *buf) { unsigned long lbuf; - acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf); - if(ACPI_FAILURE(status)) { + acpi_status status = acpi_evaluate_integer(dock_station->handle, + "_UID", NULL, &lbuf); + if (ACPI_FAILURE(status)) return 0; - } + return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); } DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); - - /** * dock_add - add a new dock station * @handle: the dock station handle @@ -711,33 +751,53 @@ static int dock_add(acpi_handle handle) ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); /* initialize platform device stuff */ - dock_device.name = dock_device_name; - ret = platform_device_register(&dock_device); + dock_device = + platform_device_register_simple(dock_device_name, 0, NULL, 0); + if (IS_ERR(dock_device)) { + kfree(dock_station); + dock_station = NULL; + return PTR_ERR(dock_device); + } + + /* we want the dock device to send uevents */ + dock_device->dev.uevent_suppress = 0; + + ret = device_create_file(&dock_device->dev, &dev_attr_docked); if (ret) { - printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret); + printk("Error %d adding sysfs file\n", ret); + platform_device_unregister(dock_device); kfree(dock_station); + dock_station = NULL; return ret; } - ret = device_create_file(&dock_device.dev, &dev_attr_docked); + ret = device_create_file(&dock_device->dev, &dev_attr_undock); if (ret) { printk("Error %d adding sysfs file\n", ret); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + platform_device_unregister(dock_device); kfree(dock_station); + dock_station = NULL; return ret; } - ret = device_create_file(&dock_device.dev, &dev_attr_undock); + ret = device_create_file(&dock_device->dev, &dev_attr_uid); if (ret) { printk("Error %d adding sysfs file\n", ret); - device_remove_file(&dock_device.dev, &dev_attr_docked); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + platform_device_unregister(dock_device); kfree(dock_station); + dock_station = NULL; return ret; } - ret = device_create_file(&dock_device.dev, &dev_attr_uid); + ret = device_create_file(&dock_device->dev, &dev_attr_flags); if (ret) { printk("Error %d adding sysfs file\n", ret); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + device_remove_file(&dock_device->dev, &dev_attr_uid); + platform_device_unregister(dock_device); kfree(dock_station); + dock_station = NULL; return ret; } @@ -750,6 +810,7 @@ static int dock_add(acpi_handle handle) dd = alloc_dock_dependent_device(handle); if (!dd) { kfree(dock_station); + dock_station = NULL; ret = -ENOMEM; goto dock_add_err_unregister; } @@ -773,10 +834,13 @@ static int dock_add(acpi_handle handle) dock_add_err: kfree(dd); dock_add_err_unregister: - device_remove_file(&dock_device.dev, &dev_attr_docked); - device_remove_file(&dock_device.dev, &dev_attr_undock); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + device_remove_file(&dock_device->dev, &dev_attr_uid); + device_remove_file(&dock_device->dev, &dev_attr_flags); + platform_device_unregister(dock_device); kfree(dock_station); + dock_station = NULL; return ret; } @@ -804,12 +868,15 @@ static int dock_remove(void) printk(KERN_ERR "Error removing notify handler\n"); /* cleanup sysfs */ - device_remove_file(&dock_device.dev, &dev_attr_docked); - device_remove_file(&dock_device.dev, &dev_attr_undock); - platform_device_unregister(&dock_device); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + device_remove_file(&dock_device->dev, &dev_attr_uid); + device_remove_file(&dock_device->dev, &dev_attr_flags); + platform_device_unregister(dock_device); /* free dock station memory */ kfree(dock_station); + dock_station = NULL; return 0; } diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 902c287..361ebe6 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -586,6 +586,10 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); if (gpe_xrupt->previous) { gpe_xrupt->previous->next = gpe_xrupt->next; + } else { + /* No previous, update list head */ + + acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next; } if (gpe_xrupt->next) { diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c index 1285e91..002bb33 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/tables/tbfadt.c @@ -211,14 +211,17 @@ void acpi_tb_parse_fadt(acpi_native_uint * DESCRIPTION: Get a local copy of the FADT and convert it to a common format. * Performs validation on some important FADT fields. * + * NOTE: We create a local copy of the FADT regardless of the version. + * ******************************************************************************/ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) { /* - * Check if the FADT is larger than what we know about (ACPI 2.0 version). - * Truncate the table, but make some noise. + * Check if the FADT is larger than the largest table that we expect + * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue + * a warning. */ if (length > sizeof(struct acpi_table_fadt)) { ACPI_WARNING((AE_INFO, @@ -227,10 +230,12 @@ void acpi_tb_create_local_fadt(struct ac sizeof(struct acpi_table_fadt))); } - /* Copy the entire FADT locally. Zero first for tb_convert_fadt */ + /* Clear the entire local FADT */ ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); + /* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */ + ACPI_MEMCPY(&acpi_gbl_FADT, table, ACPI_MIN(length, sizeof(struct acpi_table_fadt))); @@ -251,7 +256,7 @@ void acpi_tb_create_local_fadt(struct ac * RETURN: None * * DESCRIPTION: Converts all versions of the FADT to a common internal format. - * -> Expand all 32-bit addresses to 64-bit. + * Expand all 32-bit addresses to 64-bit. * * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), * and must contain a copy of the actual FADT. @@ -292,8 +297,23 @@ static void acpi_tb_convert_fadt(void) } /* - * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address - * structures as necessary. + * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which + * should be zero are indeed zero. This will workaround BIOSs that + * inadvertently place values in these fields. + * + * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at + * offset 45, 55, 95, and the word located at offset 109, 110. + */ + if (acpi_gbl_FADT.header.revision < 3) { + acpi_gbl_FADT.preferred_profile = 0; + acpi_gbl_FADT.pstate_control = 0; + acpi_gbl_FADT.cst_control = 0; + acpi_gbl_FADT.boot_flags = 0; + } + + /* + * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X" + * generic address structures as necessary. */ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { target = @@ -349,18 +369,6 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.xpm1a_event_block.space_id; } - - /* - * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero) - * are indeed zero. This will workaround BIOSs that inadvertently placed - * values in these fields. - */ - if (acpi_gbl_FADT.header.revision < 3) { - acpi_gbl_FADT.preferred_profile = 0; - acpi_gbl_FADT.pstate_control = 0; - acpi_gbl_FADT.cst_control = 0; - acpi_gbl_FADT.boot_flags = 0; - } } /****************************************************************************** diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 4c1e008..879eaa1 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -68,6 +68,10 @@ acpi_ut_copy_esimple_to_isimple(union ac union acpi_operand_object **return_obj); static acpi_status +acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, + union acpi_operand_object **internal_object); + +static acpi_status acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, union acpi_operand_object *dest_desc); @@ -518,77 +522,73 @@ acpi_ut_copy_esimple_to_isimple(union ac return_ACPI_STATUS(AE_NO_MEMORY); } -#ifdef ACPI_FUTURE_IMPLEMENTATION -/* Code to convert packages that are parameters to control methods */ - /******************************************************************************* * * FUNCTION: acpi_ut_copy_epackage_to_ipackage * - * PARAMETERS: *internal_object - Pointer to the object we are returning - * *Buffer - Where the object is returned - * *space_used - Where the length of the object is returned + * PARAMETERS: external_object - The external object to be converted + * internal_object - Where the internal object is returned * * RETURN: Status * - * DESCRIPTION: This function is called to place a package object in a user - * buffer. A package object by definition contains other objects. - * - * The buffer is assumed to have sufficient space for the object. - * The caller must have verified the buffer length needed using the - * acpi_ut_get_object_size function before calling this function. + * DESCRIPTION: Copy an external package object to an internal package. + * Handles nested packages. * ******************************************************************************/ static acpi_status -acpi_ut_copy_epackage_to_ipackage(union acpi_operand_object *internal_object, - u8 * buffer, u32 * space_used) +acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, + union acpi_operand_object **internal_object) { - u8 *free_space; - union acpi_object *external_object; - u32 length = 0; - u32 this_index; - u32 object_space = 0; - union acpi_operand_object *this_internal_obj; - union acpi_object *this_external_obj; + acpi_status status = AE_OK; + union acpi_operand_object *package_object; + union acpi_operand_object **package_elements; + acpi_native_uint i; ACPI_FUNCTION_TRACE(ut_copy_epackage_to_ipackage); - /* - * First package at head of the buffer - */ - external_object = (union acpi_object *)buffer; + /* Create the package object */ - /* - * Free space begins right after the first package - */ - free_space = buffer + sizeof(union acpi_object); + package_object = + acpi_ut_create_package_object(external_object->package.count); + if (!package_object) { + return_ACPI_STATUS(AE_NO_MEMORY); + } - external_object->type = ACPI_GET_OBJECT_TYPE(internal_object); - external_object->package.count = internal_object->package.count; - external_object->package.elements = (union acpi_object *)free_space; + package_elements = package_object->package.elements; /* - * Build an array of ACPI_OBJECTS in the buffer - * and move the free space past it + * Recursive implementation. Probably ok, since nested external packages + * as parameters should be very rare. */ - free_space += - external_object->package.count * sizeof(union acpi_object); + for (i = 0; i < external_object->package.count; i++) { + status = + acpi_ut_copy_eobject_to_iobject(&external_object->package. + elements[i], + &package_elements[i]); + if (ACPI_FAILURE(status)) { - /* Call walk_package */ + /* Truncate package and delete it */ -} + package_object->package.count = i; + package_elements[i] = NULL; + acpi_ut_remove_reference(package_object); + return_ACPI_STATUS(status); + } + } -#endif /* Future implementation */ + *internal_object = package_object; + return_ACPI_STATUS(status); +} /******************************************************************************* * * FUNCTION: acpi_ut_copy_eobject_to_iobject * - * PARAMETERS: *internal_object - The external object to be converted - * *buffer_ptr - Where the internal object is returned + * PARAMETERS: external_object - The external object to be converted + * internal_object - Where the internal object is returned * - * RETURN: Status - the status of the call + * RETURN: Status - the status of the call * * DESCRIPTION: Converts an external object to an internal object. * @@ -603,16 +603,10 @@ acpi_ut_copy_eobject_to_iobject(union ac ACPI_FUNCTION_TRACE(ut_copy_eobject_to_iobject); if (external_object->type == ACPI_TYPE_PACKAGE) { - /* - * Packages as external input to control methods are not supported, - */ - ACPI_ERROR((AE_INFO, - "Packages as parameters not implemented!")); - - return_ACPI_STATUS(AE_NOT_IMPLEMENTED); - } - - else { + status = + acpi_ut_copy_epackage_to_ipackage(external_object, + internal_object); + } else { /* * Build a simple object (no nested objects) */ @@ -803,33 +797,19 @@ acpi_ut_copy_ielement_to_ielement(u8 obj * Create and build the package object */ target_object = - acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE); + acpi_ut_create_package_object(source_object->package.count); if (!target_object) { return (AE_NO_MEMORY); } - target_object->package.count = source_object->package.count; target_object->common.flags = source_object->common.flags; - /* - * Create the object array - */ - target_object->package.elements = - ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package. - count + 1) * sizeof(void *)); - if (!target_object->package.elements) { - status = AE_NO_MEMORY; - goto error_exit; - } + /* Pass the new package object back to the package walk routine */ - /* - * Pass the new package object back to the package walk routine - */ state->pkg.this_target_obj = target_object; - /* - * Store the object pointer in the parent package object - */ + /* Store the object pointer in the parent package object */ + *this_target_ptr = target_object; break; diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index 13d5879..7ec6eb6 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -63,16 +63,13 @@ static const char *acpi_interfaces_suppo /* Operating System Vendor Strings */ "Linux", - "Windows 2000", - "Windows 2001", - "Windows 2001 SP0", - "Windows 2001 SP1", - "Windows 2001 SP2", - "Windows 2001 SP3", - "Windows 2001 SP4", - "Windows 2001.1", - "Windows 2001.1 SP1", /* Added 03/2006 */ - "Windows 2006", /* Added 03/2006 */ + "Windows 2000", /* Windows 2000 */ + "Windows 2001", /* Windows XP */ + "Windows 2001 SP1", /* Windows XP SP1 */ + "Windows 2001 SP2", /* Windows XP SP2 */ + "Windows 2001.1", /* Windows Server 2003 */ + "Windows 2001.1 SP1", /* Windows Server 2003 SP1 - Added 03/2006 */ + "Windows 2006", /* Windows Vista - Added 03/2006 */ /* Feature Group Strings */ diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index 4696124..db0b9ba 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -146,6 +146,48 @@ union acpi_operand_object *acpi_ut_creat /******************************************************************************* * + * FUNCTION: acpi_ut_create_package_object + * + * PARAMETERS: Count - Number of package elements + * + * RETURN: Pointer to a new Package object, null on failure + * + * DESCRIPTION: Create a fully initialized package object + * + ******************************************************************************/ + +union acpi_operand_object *acpi_ut_create_package_object(u32 count) +{ + union acpi_operand_object *package_desc; + union acpi_operand_object **package_elements; + + ACPI_FUNCTION_TRACE_U32(ut_create_package_object, count); + + /* Create a new Package object */ + + package_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE); + if (!package_desc) { + return_PTR(NULL); + } + + /* + * Create the element array. Count+1 allows the array to be null + * terminated. + */ + package_elements = ACPI_ALLOCATE_ZEROED((acpi_size) + (count + 1) * sizeof(void *)); + if (!package_elements) { + ACPI_FREE(package_desc); + return_PTR(NULL); + } + + package_desc->package.count = count; + package_desc->package.elements = package_elements; + return_PTR(package_desc); +} + +/******************************************************************************* + * * FUNCTION: acpi_ut_create_buffer_object * * PARAMETERS: buffer_size - Size of buffer to be created diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 00d25b3..39273da 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -169,6 +170,7 @@ struct acpi_video_device { struct acpi_device *dev; struct acpi_video_device_brightness *brightness; struct backlight_device *backlight; + struct output_device *output_dev; }; /* bus */ @@ -272,6 +274,10 @@ static int acpi_video_get_next_level(str u32 level_current, u32 event); static void acpi_video_switch_brightness(struct acpi_video_device *device, int event); +static int acpi_video_device_get_state(struct acpi_video_device *device, + unsigned long *state); +static int acpi_video_output_get(struct output_device *od); +static int acpi_video_device_set_state(struct acpi_video_device *device, int state); /*backlight device sysfs support*/ static int acpi_video_get_brightness(struct backlight_device *bd) @@ -297,6 +303,28 @@ static struct backlight_ops acpi_backlig .update_status = acpi_video_set_brightness, }; +/*video output device sysfs support*/ +static int acpi_video_output_get(struct output_device *od) +{ + unsigned long state; + struct acpi_video_device *vd = + (struct acpi_video_device *)class_get_devdata(&od->class_dev); + acpi_video_device_get_state(vd, &state); + return (int)state; +} + +static int acpi_video_output_set(struct output_device *od) +{ + unsigned long state = od->request_state; + struct acpi_video_device *vd= + (struct acpi_video_device *)class_get_devdata(&od->class_dev); + return acpi_video_device_set_state(vd, state); +} + +static struct output_properties acpi_output_properties = { + .set_state = acpi_video_output_set, + .get_status = acpi_video_output_get, +}; /* -------------------------------------------------------------------------- Video Management -------------------------------------------------------------------------- */ @@ -626,6 +654,17 @@ static void acpi_video_device_find_cap(s kfree(name); } + if (device->cap._DCS && device->cap._DSS){ + static int count = 0; + char *name; + name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); + if (!name) + return; + sprintf(name, "acpi_video%d", count++); + device->output_dev = video_output_register(name, + NULL, device, &acpi_output_properties); + kfree(name); + } return; } @@ -1669,6 +1708,7 @@ static int acpi_video_bus_put_one_device ACPI_DEVICE_NOTIFY, acpi_video_device_notify); backlight_device_unregister(device->backlight); + video_output_unregister(device->output_dev); return 0; } diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6e1f1ea..f4f82f2 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -12,6 +12,13 @@ config VGASTATE tristate default n +config VIDEO_OUTPUT_CONTROL + tristate "Lowlevel video output switch controls" + default m + help + This framework adds support for low-level control of the video + output switch. + config FB tristate "Support for frame buffer devices" ---help--- diff --git a/drivers/video/Makefile b/drivers/video/Makefile index bd8b052..d955074 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -122,3 +122,6 @@ obj-$(CONFIG_FB_OF) += off # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o + +#video output switch sysfs driver +obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h index 15a8388..a87ef1c 100644 --- a/include/acpi/acutils.h +++ b/include/acpi/acutils.h @@ -390,6 +390,8 @@ void acpi_ut_delete_object_desc(union ac u8 acpi_ut_valid_internal_object(void *object); +union acpi_operand_object *acpi_ut_create_package_object(u32 count); + union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size); union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size); diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index dab2ec5..c785485 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -136,7 +136,7 @@ #endif /*! [Begin] no source code translation */ -#if defined(__linux__) +#if defined(_LINUX) || defined(__linux__) #include "aclinux.h" #elif defined(_AED_EFI) diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index a568717..6ed15a0 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -91,7 +91,10 @@ #define COMPILER_DEPENDENT_UINT64 unsi #define ACPI_USE_NATIVE_DIVIDE #endif +#ifndef __cdecl #define __cdecl +#endif + #define ACPI_FLUSH_CPU_CACHE() #endif /* __KERNEL__ */