diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/Kconfig | 23 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 673 | ||||
-rw-r--r-- | drivers/acpi/bay.c | 19 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 4 | ||||
-rw-r--r-- | drivers/acpi/dock.c | 127 | ||||
-rw-r--r-- | drivers/acpi/ec.c | 247 | ||||
-rw-r--r-- | drivers/acpi/event.c | 153 | ||||
-rw-r--r-- | drivers/acpi/events/evgpeblk.c | 4 | ||||
-rw-r--r-- | drivers/acpi/events/evrgnini.c | 1 | ||||
-rw-r--r-- | drivers/acpi/glue.c | 2 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 40 | ||||
-rw-r--r-- | drivers/acpi/pci_link.c | 2 | ||||
-rw-r--r-- | drivers/acpi/processor_core.c | 6 | ||||
-rw-r--r-- | drivers/acpi/processor_idle.c | 20 | ||||
-rw-r--r-- | drivers/acpi/processor_throttling.c | 410 | ||||
-rw-r--r-- | drivers/acpi/sbs.c | 33 | ||||
-rw-r--r-- | drivers/acpi/sleep/main.c | 5 | ||||
-rw-r--r-- | drivers/acpi/tables/tbfadt.c | 44 | ||||
-rw-r--r-- | drivers/acpi/utilities/uteval.c | 17 | ||||
-rw-r--r-- | drivers/acpi/video.c | 120 |
20 files changed, 1398 insertions, 552 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 139f41f033d..408b45168ab 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -2,16 +2,12 @@ # ACPI Configuration # -menu "ACPI (Advanced Configuration and Power Interface) Support" +menuconfig ACPI + bool "ACPI Support (Advanced Configuration and Power Interface) Support" depends on !X86_NUMAQ depends on !X86_VISWS depends on !IA64_HP_SIM depends on IA64 || X86 - depends on PM - -config ACPI - bool "ACPI Support" - depends on IA64 || X86 depends on PCI depends on PM select PNP @@ -49,7 +45,6 @@ if ACPI config ACPI_SLEEP bool "Sleep States" depends on X86 && (!SMP || SUSPEND_SMP) - depends on PM default y ---help--- This option adds support for ACPI suspend states. @@ -82,7 +77,6 @@ config ACPI_SLEEP_PROC_SLEEP config ACPI_PROCFS bool "Procfs interface (deprecated)" - depends on ACPI default y ---help--- The Procfs interface for ACPI is made optional for backward compatibility. @@ -124,7 +118,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 @@ -280,6 +274,14 @@ config ACPI_DEBUG of verbosity. Saying Y enables these statements. This will increase your kernel size by around 50K. +config ACPI_DEBUG_FUNC_TRACE + bool "Additionally enable ACPI function tracing" + default n + depends on ACPI_DEBUG + help + ACPI Debug Statements slow down ACPI processing. Function trace + is about half of the penalty and is rarely useful. + config ACPI_EC bool default y @@ -330,7 +332,6 @@ config ACPI_CONTAINER config ACPI_HOTPLUG_MEMORY tristate "Memory Hotplug" - depends on ACPI depends on MEMORY_HOTPLUG default n help @@ -359,5 +360,3 @@ config ACPI_SBS to today's ACPI "Control Method" battery. endif # ACPI - -endmenu diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index e64c76c8b72..cad932de383 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -43,21 +43,30 @@ #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_driver = { }, }; -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_battery *battery, 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_battery *battery, 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_battery *battery, 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_battery *battery, 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_battery *battery, unsigned long alarm) 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(struct acpi_battery *battery) -------------------------------------------------------------------------- */ 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 seq_file *seq, void *offset) 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_file *seq, void *offset) 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(struct seq_file *seq, void *offset) (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 *file, 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(struct inode *inode, struct file *file) 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 acpi_device *device) 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 acpi_device *device) 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_handle handle, u32 event, void *data) struct acpi_battery *battery = data; struct acpi_device *device = NULL; - if (!battery) return; @@ -684,8 +865,10 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) 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_device *device) acpi_status status = 0; struct acpi_battery *battery = NULL; - if (!device) return -EINVAL; @@ -710,15 +892,21 @@ static int acpi_battery_add(struct acpi_device *device) 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_device *device) 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 *device) 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 acpi_device *device, int type) 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 acpi_device *device) 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 fb3f31b5e69..56a5b3fffeb 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -288,6 +288,11 @@ static int bay_add(acpi_handle handle, int id) 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; @@ -328,18 +333,12 @@ static void bay_notify(acpi_handle handle, u32 event, void *data) { struct bay *bay_dev = (struct bay *)data; struct device *dev = &bay_dev->pdev->dev; + char event_string[12]; + char *envp[] = { event_string, NULL }; bay_dprintk(handle, "Bay event"); - - switch(event) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - case ACPI_NOTIFY_EJECT_REQUEST: - kobject_uevent(&dev->kobj, KOBJ_CHANGE); - break; - default: - printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event); - } + sprintf(event_string, "BAY_EVENT=%d\n", event); + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } static acpi_status diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index e5084ececb6..6b2658c9624 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -292,6 +292,10 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data) if (!device) return -EINVAL; + if (acpi_bus_generate_genetlink_event(device, type, data)) + printk(KERN_WARNING PREFIX + "Failed to generate an ACPI event via genetlink!\n"); + /* drop event on the floor if no one's listening */ if (!event_is_open) return 0; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 4546bf873ae..6192c8be66d 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 dock_station *ds, u32 event) 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); } /** @@ -380,12 +396,11 @@ static void handle_dock(struct dock_station *ds, int dock) union acpi_object arg; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); - obj = name_buffer.pointer; - printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking"); + printk(KERN_INFO PREFIX "%s - %s\n", + (char *)name_buffer.pointer, dock ? "docking" : "undocking"); /* _DCK method has one argument */ arg_list.count = 1; @@ -394,7 +409,8 @@ static void handle_dock(struct dock_station *ds, int dock) arg.integer.value = dock; status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); if (ACPI_FAILURE(status)) - pr_debug("%s: failed to execute _DCK\n", obj->string.pointer); + printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", + (char *)name_buffer.pointer); kfree(buffer.pointer); kfree(name_buffer.pointer); } @@ -420,6 +436,16 @@ static inline void complete_dock(struct dock_station *ds) 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 dock_station *ds, u32 event) 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 handle, u32 event, void *data) * 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 *dev, 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 device *dev, 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/ec.c b/drivers/acpi/ec.c index 82f496c0767..10e851021ec 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -34,25 +34,26 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/interrupt.h> +#include <linux/list.h> #include <asm/io.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> #include <acpi/actypes.h> -#define _COMPONENT ACPI_EC_COMPONENT -ACPI_MODULE_NAME("ec"); -#define ACPI_EC_COMPONENT 0x00100000 #define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_HID "PNP0C09" #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" + #undef PREFIX #define PREFIX "ACPI: EC: " + /* EC status register */ #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ + /* EC commands */ enum ec_command { ACPI_EC_COMMAND_READ = 0x80, @@ -61,6 +62,7 @@ enum ec_command { ACPI_EC_BURST_DISABLE = 0x83, ACPI_EC_COMMAND_QUERY = 0x84, }; + /* EC events */ enum ec_event { ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ @@ -94,6 +96,16 @@ static struct acpi_driver acpi_ec_driver = { /* If we find an EC via the ECDT, we need to keep a ptr to its context */ /* External interfaces use first EC only, so remember */ +typedef int (*acpi_ec_query_func) (void *data); + +struct acpi_ec_query_handler { + struct list_head node; + acpi_ec_query_func func; + acpi_handle handle; + void *data; + u8 query_bit; +}; + static struct acpi_ec { acpi_handle handle; unsigned long gpe; @@ -104,6 +116,7 @@ static struct acpi_ec { atomic_t query_pending; atomic_t event_count; wait_queue_head_t wait; + struct list_head list; } *boot_ec, *first_ec; /* -------------------------------------------------------------------------- @@ -245,7 +258,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0); if (status) { - printk(KERN_DEBUG PREFIX + printk(KERN_ERR PREFIX "input buffer is not empty, aborting transaction\n"); goto end; } @@ -394,21 +407,67 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ +int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, + acpi_handle handle, acpi_ec_query_func func, + void *data) +{ + struct acpi_ec_query_handler *handler = + kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL); + if (!handler) + return -ENOMEM; + + handler->query_bit = query_bit; + handler->handle = handle; + handler->func = func; + handler->data = data; + mutex_lock(&ec->lock); + list_add_tail(&handler->node, &ec->list); + mutex_unlock(&ec->lock); + return 0; +} + +EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); + +void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) +{ + struct acpi_ec_query_handler *handler; + mutex_lock(&ec->lock); + list_for_each_entry(handler, &ec->list, node) { + if (query_bit == handler->query_bit) { + list_del(&handler->node); + kfree(handler); + break; + } + } + mutex_unlock(&ec->lock); +} + +EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); static void acpi_ec_gpe_query(void *ec_cxt) { struct acpi_ec *ec = ec_cxt; u8 value = 0; - char object_name[8]; + struct acpi_ec_query_handler *handler, copy; if (!ec || acpi_ec_query(ec, &value)) return; - - snprintf(object_name, 8, "_Q%2.2X", value); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); - - acpi_evaluate_object(ec->handle, object_name, NULL, NULL); + mutex_lock(&ec->lock); + list_for_each_entry(handler, &ec->list, node) { + if (value == handler->query_bit) { + /* have custom handler for this bit */ + memcpy(©, handler, sizeof(copy)); + mutex_unlock(&ec->lock); + if (copy.func) { + copy.func(copy.data); + } else if (copy.handle) { + acpi_evaluate_object(copy.handle, NULL, NULL, NULL); + } + return; + } + } + mutex_unlock(&ec->lock); + printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value); } static u32 acpi_ec_gpe_handler(void *data) @@ -427,8 +486,7 @@ static u32 acpi_ec_gpe_handler(void *data) if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { atomic_set(&ec->query_pending, 1); status = - acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, - ec); + acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); } return status == AE_OK ? @@ -454,57 +512,35 @@ acpi_ec_space_setup(acpi_handle region_handle, } static acpi_status -acpi_ec_space_handler(u32 function, - acpi_physical_address address, - u32 bit_width, - acpi_integer * value, +acpi_ec_space_handler(u32 function, acpi_physical_address address, + u32 bits, acpi_integer *value, void *handler_context, void *region_context) { - int result = 0; struct acpi_ec *ec = handler_context; - u64 temp = *value; - acpi_integer f_v = 0; - int i = 0; + int result = 0, i = 0; + u8 temp = 0; if ((address > 0xFF) || !value || !handler_context) return AE_BAD_PARAMETER; - if (bit_width != 8 && acpi_strict) { + if (function != ACPI_READ && function != ACPI_WRITE) return AE_BAD_PARAMETER; - } - - next_byte: - switch (function) { - case ACPI_READ: - temp = 0; - result = acpi_ec_read(ec, (u8) address, (u8 *) & temp); - break; - case ACPI_WRITE: - result = acpi_ec_write(ec, (u8) address, (u8) temp); - break; - default: - result = -EINVAL; - goto out; - break; - } - bit_width -= 8; - if (bit_width) { - if (function == ACPI_READ) - f_v |= temp << 8 * i; - if (function == ACPI_WRITE) - temp >>= 8; - i++; - address++; - goto next_byte; - } + if (bits != 8 && acpi_strict) + return AE_BAD_PARAMETER; - if (function == ACPI_READ) { - f_v |= temp << 8 * i; - *value = f_v; + while (bits - i > 0) { + if (function == ACPI_READ) { + result = acpi_ec_read(ec, address, &temp); + (*value) |= ((acpi_integer)temp) << i; + } else { + temp = 0xff & ((*value) >> i); + result = acpi_ec_write(ec, address, temp); + } + i += 8; + ++address; } - out: switch (result) { case -EINVAL: return AE_BAD_PARAMETER; @@ -597,9 +633,6 @@ static int acpi_ec_remove_fs(struct acpi_device *device) static acpi_status ec_parse_io_ports(struct acpi_resource *resource, void *context); -static acpi_status -ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval); - static struct acpi_ec *make_acpi_ec(void) { struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); @@ -610,13 +643,52 @@ static struct acpi_ec *make_acpi_ec(void) atomic_set(&ec->event_count, 1); mutex_init(&ec->lock); init_waitqueue_head(&ec->wait); + INIT_LIST_HEAD(&ec->list); return ec; } +static acpi_status +acpi_ec_register_query_methods(acpi_handle handle, u32 level, + void *context, void **return_value) +{ + struct acpi_namespace_node *node = handle; + struct acpi_ec *ec = context; + int value = 0; + if (sscanf(node->name.ascii, "_Q%x", &value) == 1) { + acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); + } + return AE_OK; +} + +static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle) +{ + if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS, + ec_parse_io_ports, ec))) + return -EINVAL; + + /* Get GPE bit assignment (EC events). */ + /* TODO: Add support for _GPE returning a package */ + if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe))) + return -EINVAL; + + /* Use the global lock for all EC transactions? */ + acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); + + /* Find and register all query methods */ + acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, + acpi_ec_register_query_methods, ec, NULL); + + ec->handle = handle; + + printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", + ec->gpe, ec->command_addr, ec->data_addr); + + return 0; +} + static int acpi_ec_add(struct acpi_device *device) { - acpi_status status = AE_OK; struct acpi_ec *ec = NULL; if (!device) @@ -629,8 +701,7 @@ static int acpi_ec_add(struct acpi_device *device) if (!ec) return -ENOMEM; - status = ec_parse_device(device->handle, 0, ec, NULL); - if (status != AE_CTRL_TERMINATE) { + if (ec_parse_device(ec, device->handle)) { kfree(ec); return -EINVAL; } @@ -641,6 +712,8 @@ static int acpi_ec_add(struct acpi_device *device) /* We might have incorrect info for GL at boot time */ mutex_lock(&boot_ec->lock); boot_ec->global_lock = ec->global_lock; + /* Copy handlers from new ec into boot ec */ + list_splice(&ec->list, &boot_ec->list); mutex_unlock(&boot_ec->lock); kfree(ec); ec = boot_ec; @@ -651,22 +724,24 @@ static int acpi_ec_add(struct acpi_device *device) acpi_driver_data(device) = ec; acpi_ec_add_fs(device); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", - acpi_device_name(device), acpi_device_bid(device), - (u32) ec->gpe)); - return 0; } static int acpi_ec_remove(struct acpi_device *device, int type) { struct acpi_ec *ec; + struct acpi_ec_query_handler *handler; if (!device) return -EINVAL; ec = acpi_driver_data(device); + mutex_lock(&ec->lock); + list_for_each_entry(handler, &ec->list, node) { + list_del(&handler->node); + kfree(handler); + } + mutex_unlock(&ec->lock); acpi_ec_remove_fs(device); acpi_driver_data(device) = NULL; if (ec == first_ec) @@ -722,15 +797,13 @@ static int ec_install_handlers(struct acpi_ec *ec) return -ENODEV; } - /* EC is fully operational, allow queries */ - atomic_set(&ec->query_pending, 0); - return 0; } static int acpi_ec_start(struct acpi_device *device) { struct acpi_ec *ec; + int ret = 0; if (!device) return -EINVAL; @@ -740,14 +813,14 @@ static int acpi_ec_start(struct acpi_device *device) if (!ec) return -EINVAL; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", - ec->gpe, ec->command_addr, ec->data_addr)); - /* Boot EC is already working */ - if (ec == boot_ec) - return 0; + if (ec != boot_ec) + ret = ec_install_handlers(ec); + + /* EC is fully operational, allow queries */ + atomic_set(&ec->query_pending, 0); - return ec_install_handlers(ec); + return ret; } static int acpi_ec_stop(struct acpi_device *device, int type) @@ -779,34 +852,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type) return 0; } -static acpi_status -ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) -{ - acpi_status status; - - struct acpi_ec *ec = context; - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - ec_parse_io_ports, ec); - if (ACPI_FAILURE(status)) - return status; - - /* Get GPE bit assignment (EC events). */ - /* TODO: Add support for _GPE returning a package */ - status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); - if (ACPI_FAILURE(status)) - return status; - - /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); - - ec->handle = handle; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx", - ec->gpe, ec->command_addr, ec->data_addr)); - - return AE_CTRL_TERMINATE; -} - int __init acpi_ec_ecdt_probe(void) { int ret; @@ -825,7 +870,7 @@ int __init acpi_ec_ecdt_probe(void) if (ACPI_FAILURE(status)) goto error; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT")); + printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n"); boot_ec->command_addr = ecdt_ptr->control.address; boot_ec->data_addr = ecdt_ptr->data.address; diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 3b23562e6f9..dfa5853b17f 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -11,6 +11,8 @@ #include <linux/init.h> #include <linux/poll.h> #include <acpi/acpi_drivers.h> +#include <net/netlink.h> +#include <net/genetlink.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("event"); @@ -48,7 +50,6 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count, static int chars_remaining = 0; static char *ptr; - if (!chars_remaining) { memset(&event, 0, sizeof(struct acpi_bus_event)); @@ -106,23 +107,161 @@ static const struct file_operations acpi_system_event_ops = { .poll = acpi_system_poll_event, }; +#ifdef CONFIG_NET +unsigned int acpi_event_seqnum; +struct acpi_genl_event { + acpi_device_class device_class; + char bus_id[15]; + u32 type; + u32 data; +}; + +/* attributes of acpi_genl_family */ +enum { + ACPI_GENL_ATTR_UNSPEC, + ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */ + __ACPI_GENL_ATTR_MAX, +}; +#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1) + +/* commands supported by the acpi_genl_family */ +enum { + ACPI_GENL_CMD_UNSPEC, + ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */ + __ACPI_GENL_CMD_MAX, +}; +#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1) + +#define ACPI_GENL_FAMILY_NAME "acpi_event" +#define ACPI_GENL_VERSION 0x01 +#define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group" + +static struct genl_family acpi_event_genl_family = { + .id = GENL_ID_GENERATE, + .name = ACPI_GENL_FAMILY_NAME, + .version = ACPI_GENL_VERSION, + .maxattr = ACPI_GENL_ATTR_MAX, +}; + +static struct genl_multicast_group acpi_event_mcgrp = { + .name = ACPI_GENL_MCAST_GROUP_NAME, +}; + +int acpi_bus_generate_genetlink_event(struct acpi_device *device, + u8 type, int data) +{ + struct sk_buff *skb; + struct nlattr *attr; + struct acpi_genl_event *event; + void *msg_header; + int size; + int result; + + /* allocate memory */ + size = nla_total_size(sizeof(struct acpi_genl_event)) + + nla_total_size(0); + + skb = genlmsg_new(size, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + /* add the genetlink message header */ + msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++, + &acpi_event_genl_family, 0, + ACPI_GENL_CMD_EVENT); + if (!msg_header) { + nlmsg_free(skb); + return -ENOMEM; + } + + /* fill the data */ + attr = + nla_reserve(skb, ACPI_GENL_ATTR_EVENT, + sizeof(struct acpi_genl_event)); + if (!attr) { + nlmsg_free(skb); + return -EINVAL; + } + + event = nla_data(attr); + if (!event) { + nlmsg_free(skb); + return -EINVAL; + } + + memset(event, 0, sizeof(struct acpi_genl_event)); + + strcpy(event->device_class, device->pnp.device_class); + strcpy(event->bus_id, device->dev.bus_id); + event->type = type; + event->data = data; + + /* send multicast genetlink message */ + result = genlmsg_end(skb, msg_header); + if (result < 0) { + nlmsg_free(skb); + return result; + } + + result = + genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC); + if (result) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Failed to send a Genetlink message!\n")); + return 0; +} + +static int acpi_event_genetlink_init(void) +{ + int result; + + result = genl_register_family(&acpi_event_genl_family); + if (result) + return result; + + result = genl_register_mc_group(&acpi_event_genl_family, + &acpi_event_mcgrp); + if (result) + genl_unregister_family(&acpi_event_genl_family); + + return result; +} + +#else +int acpi_bus_generate_genetlink_event(struct acpi_device *device, u8 type, + int data) +{ + return 0; +} + +static int acpi_event_genetlink_init(void) +{ + return -ENODEV; +} +#endif + static int __init acpi_event_init(void) { struct proc_dir_entry *entry; int error = 0; - if (acpi_disabled) return 0; + /* create genetlink for acpi event */ + error = acpi_event_genetlink_init(); + if (error) + printk(KERN_WARNING PREFIX + "Failed to create genetlink family for ACPI event\n"); + /* 'event' [R] */ entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); if (entry) entry->proc_fops = &acpi_system_event_ops; - else { - error = -ENODEV; - } - return error; + else + return -ENODEV; + + return 0; } -subsys_initcall(acpi_event_init); +fs_initcall(acpi_event_init); diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 902c287b3a4..361ebe6c4a6 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_xrupt_info *gpe_xrupt) 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/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 400d90fca96..23ee7bc4a70 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -284,6 +284,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, } if (!pci_device_node) { + ACPI_FREE(pci_id); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 41427a41f62..4893e256e39 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -16,7 +16,7 @@ #if ACPI_GLUE_DEBUG #define DBG(x...) printk(PREFIX x) #else -#define DBG(x...) +#define DBG(x...) do { } while(0) #endif static LIST_HEAD(bus_type_list); static DECLARE_RWSEM(bus_type_sem); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 00d53c2fd1e..12c09fafce9 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -77,13 +77,7 @@ static struct workqueue_struct *kacpi_notify_wq; #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ static char osi_additional_string[OSI_STRING_LENGTH_MAX]; -#define OSI_LINUX_ENABLED -#ifdef OSI_LINUX_ENABLED -int osi_linux = 1; /* enable _OSI(Linux) by default */ -#else -int osi_linux; /* disable _OSI(Linux) by default */ -#endif - +static int osi_linux; /* disable _OSI(Linux) by default */ #ifdef CONFIG_DMI static struct __initdata dmi_system_id acpi_osl_dmi_table[]; @@ -1183,17 +1177,10 @@ acpi_os_validate_interface (char *interface) if (!strcmp("Linux", interface)) { printk(KERN_WARNING PREFIX "System BIOS is requesting _OSI(Linux)\n"); -#ifdef OSI_LINUX_ENABLED - printk(KERN_WARNING PREFIX - "Please test with \"acpi_osi=!Linux\"\n" - "Please send dmidecode " - "to linux-acpi@vger.kernel.org\n"); -#else printk(KERN_WARNING PREFIX "If \"acpi_osi=Linux\" works better,\n" "Please send dmidecode " "to linux-acpi@vger.kernel.org\n"); -#endif if(osi_linux) return AE_OK; } @@ -1227,36 +1214,14 @@ acpi_os_validate_address ( } #ifdef CONFIG_DMI -#ifdef OSI_LINUX_ENABLED -static int dmi_osi_not_linux(struct dmi_system_id *d) -{ - printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident); - enable_osi_linux(0); - return 0; -} -#else static int dmi_osi_linux(struct dmi_system_id *d) { - printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident); + printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident); enable_osi_linux(1); return 0; } -#endif static struct dmi_system_id acpi_osl_dmi_table[] __initdata = { -#ifdef OSI_LINUX_ENABLED - /* - * Boxes that need NOT _OSI(Linux) - */ - { - .callback = dmi_osi_not_linux, - .ident = "Toshiba Satellite P100", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"), - }, - }, -#else /* * Boxes that need _OSI(Linux) */ @@ -1268,7 +1233,6 @@ static struct dmi_system_id acpi_osl_dmi_table[] __initdata = { DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"), }, }, -#endif {} }; #endif /* CONFIG_DMI */ diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index acc59477137..3448edd61dc 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -733,7 +733,7 @@ static int acpi_pci_link_add(struct acpi_device *device) /* query and set link->irq.active */ acpi_pci_link_get_current(link); - printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), + printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device), acpi_device_bid(device)); for (i = 0; i < link->irq.possible_count; i++) { if (link->irq.active == link->irq.possible[i]) { diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e1ca86dfdd6..81aceb5da7c 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -66,6 +66,7 @@ #define ACPI_PROCESSOR_FILE_LIMIT "limit" #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 +#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82 #define ACPI_PROCESSOR_LIMIT_USER 0 #define ACPI_PROCESSOR_LIMIT_THERMAL 1 @@ -84,6 +85,8 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file); static void acpi_processor_notify(acpi_handle handle, u32 event, void *data); static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); static int acpi_processor_handle_eject(struct acpi_processor *pr); +extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr); + static struct acpi_driver acpi_processor_driver = { .name = "processor", @@ -696,6 +699,9 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) acpi_processor_cst_has_changed(pr); acpi_bus_generate_event(device, event, 0); break; + case ACPI_PROCESSOR_NOTIFY_THROTTLING: + acpi_processor_tstate_has_changed(pr); + acpi_bus_generate_event(device, event, 0); default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index bb5d23be426..a898991f77c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -490,7 +490,17 @@ static void acpi_processor_idle(void) case ACPI_STATE_C3: - if (pr->flags.bm_check) { + /* + * disable bus master + * bm_check implies we need ARB_DIS + * !bm_check implies we need cache flush + * bm_control implies whether we can do ARB_DIS + * + * That leaves a case where bm_check is set and bm_control is + * not set. In that case we cannot do much, we enter C3 + * without doing anything. + */ + if (pr->flags.bm_check && pr->flags.bm_control) { if (atomic_inc_return(&c3_cpu_count) == num_online_cpus()) { /* @@ -499,7 +509,7 @@ static void acpi_processor_idle(void) */ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); } - } else { + } else if (!pr->flags.bm_check) { /* SMP with no shared cache... Invalidate cache */ ACPI_FLUSH_CPU_CACHE(); } @@ -511,7 +521,7 @@ static void acpi_processor_idle(void) acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); - if (pr->flags.bm_check) { + if (pr->flags.bm_check && pr->flags.bm_control) { /* Enable bus master arbitration */ atomic_dec(&c3_cpu_count); acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); @@ -961,9 +971,9 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, if (pr->flags.bm_check) { /* bus mastering control is necessary */ if (!pr->flags.bm_control) { + /* In this case we enter C3 without bus mastering */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 support requires bus mastering control\n")); - return; + "C3 support without bus mastering control\n")); } } else { /* diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index b33486009f4..3f55d1f90c1 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -44,17 +44,231 @@ #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_throttling"); +static int acpi_processor_get_throttling(struct acpi_processor *pr); +int acpi_processor_set_throttling(struct acpi_processor *pr, int state); + +static int acpi_processor_get_platform_limit(struct acpi_processor *pr) +{ + acpi_status status = 0; + unsigned long tpc = 0; + + if (!pr) + return -EINVAL; + status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC")); + return -ENODEV; + } + pr->throttling_platform_limit = (int)tpc; + return 0; +} + +int acpi_processor_tstate_has_changed(struct acpi_processor *pr) +{ + return acpi_processor_get_platform_limit(pr); +} + +/* -------------------------------------------------------------------------- + _PTC, _TSS, _TSD support + -------------------------------------------------------------------------- */ +static int acpi_processor_get_throttling_control(struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = 0; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *ptc = NULL; + union acpi_object obj = { 0 }; + + status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC")); + return -ENODEV; + } + + ptc = (union acpi_object *)buffer.pointer; + if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE) + || (ptc->package.count != 2)) { + printk(KERN_ERR PREFIX "Invalid _PTC data\n"); + result = -EFAULT; + goto end; + } + + /* + * control_register + */ + + obj = ptc->package.elements[0]; + + if ((obj.type != ACPI_TYPE_BUFFER) + || (obj.buffer.length < sizeof(struct acpi_ptc_register)) + || (obj.buffer.pointer == NULL)) { + printk(KERN_ERR PREFIX + "Invalid _PTC data (control_register)\n"); + result = -EFAULT; + goto end; + } + memcpy(&pr->throttling.control_register, obj.buffer.pointer, + sizeof(struct acpi_ptc_register)); + + /* + * status_register + */ + + obj = ptc->package.elements[1]; + + if ((obj.type != ACPI_TYPE_BUFFER) + || (obj.buffer.length < sizeof(struct acpi_ptc_register)) + || (obj.buffer.pointer == NULL)) { + printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n"); + result = -EFAULT; + goto end; + } + + memcpy(&pr->throttling.status_register, obj.buffer.pointer, + sizeof(struct acpi_ptc_register)); + + end: + kfree(buffer.pointer); + + return result; +} +static int acpi_processor_get_throttling_states(struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" }; + struct acpi_buffer state = { 0, NULL }; + union acpi_object *tss = NULL; + int i; + + status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS")); + return -ENODEV; + } + + tss = buffer.pointer; + if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) { + printk(KERN_ERR PREFIX "Invalid _TSS data\n"); + result = -EFAULT; + goto end; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n", + tss->package.count)); + + pr->throttling.state_count = tss->package.count; + pr->throttling.states_tss = + kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count, + GFP_KERNEL); + if (!pr->throttling.states_tss) { + result = -ENOMEM; + goto end; + } + + for (i = 0; i < pr->throttling.state_count; i++) { + + struct acpi_processor_tx_tss *tx = + (struct acpi_processor_tx_tss *)&(pr->throttling. + states_tss[i]); + + state.length = sizeof(struct acpi_processor_tx_tss); + state.pointer = tx; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); + + status = acpi_extract_package(&(tss->package.elements[i]), + &format, &state); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data")); + result = -EFAULT; + kfree(pr->throttling.states_tss); + goto end; + } + + if (!tx->freqpercentage) { + printk(KERN_ERR PREFIX + "Invalid _TSS data: freq is zero\n"); + result = -EFAULT; + kfree(pr->throttling.states_tss); + goto end; + } + } + + end: + kfree(buffer.pointer); + + return result; +} +static int acpi_processor_get_tsd(struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" }; + struct acpi_buffer state = { 0, NULL }; + union acpi_object *tsd = NULL; + struct acpi_tsd_package *pdomain; + + status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer); + if (ACPI_FAILURE(status)) { + return -ENODEV; + } + + tsd = buffer.pointer; + if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); + result = -EFAULT; + goto end; + } + + if (tsd->package.count != 1) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); + result = -EFAULT; + goto end; + } + + pdomain = &(pr->throttling.domain_info); + + state.length = sizeof(struct acpi_tsd_package); + state.pointer = pdomain; + + status = acpi_extract_package(&(tsd->package.elements[0]), + &format, &state); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); + result = -EFAULT; + goto end; + } + + if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n")); + result = -EFAULT; + goto end; + } + + if (pdomain->revision != ACPI_TSD_REV0_REVISION) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n")); + result = -EFAULT; + goto end; + } + + end: + kfree(buffer.pointer); + return result; +} + /* -------------------------------------------------------------------------- Throttling Control -------------------------------------------------------------------------- */ -static int acpi_processor_get_throttling(struct acpi_processor *pr) +static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr) { int state = 0; u32 value = 0; u32 duty_mask = 0; u32 duty_value = 0; - if (!pr) return -EINVAL; @@ -94,13 +308,115 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) return 0; } -int acpi_processor_set_throttling(struct acpi_processor *pr, int state) +static int acpi_read_throttling_status(struct acpi_processor_throttling + *throttling) +{ + int value = -1; + switch (throttling->status_register.space_id) { + case ACPI_ADR_SPACE_SYSTEM_IO: + acpi_os_read_port((acpi_io_address) throttling->status_register. + address, &value, + (u32) throttling->status_register.bit_width * + 8); + break; + case ACPI_ADR_SPACE_FIXED_HARDWARE: + printk(KERN_ERR PREFIX + "HARDWARE addr space,NOT supported yet\n"); + break; + default: + printk(KERN_ERR PREFIX "Unknown addr space %d\n", + (u32) (throttling->status_register.space_id)); + } + return value; +} + +static int acpi_write_throttling_state(struct acpi_processor_throttling + *throttling, int value) +{ + int ret = -1; + + switch (throttling->control_register.space_id) { + case ACPI_ADR_SPACE_SYSTEM_IO: + acpi_os_write_port((acpi_io_address) throttling-> + control_register.address, value, + (u32) throttling->control_register. + bit_width * 8); + ret = 0; + break; + case ACPI_ADR_SPACE_FIXED_HARDWARE: + printk(KERN_ERR PREFIX + "HARDWARE addr space,NOT supported yet\n"); + break; + default: + printk(KERN_ERR PREFIX "Unknown addr space %d\n", + (u32) (throttling->control_register.space_id)); + } + return ret; +} + +static int acpi_get_throttling_state(struct acpi_processor *pr, int value) +{ + int i; + + for (i = 0; i < pr->throttling.state_count; i++) { + struct acpi_processor_tx_tss *tx = + (struct acpi_processor_tx_tss *)&(pr->throttling. + states_tss[i]); + if (tx->control == value) + break; + } + if (i > pr->throttling.state_count) + i = -1; + return i; +} + +static int acpi_get_throttling_value(struct acpi_processor *pr, int state) +{ + int value = -1; + if (state >= 0 && state <= pr->throttling.state_count) { + struct acpi_processor_tx_tss *tx = + (struct acpi_processor_tx_tss *)&(pr->throttling. + states_tss[state]); + value = tx->control; + } + return value; +} + +static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) +{ + int state = 0; + u32 value = 0; + + if (!pr) + return -EINVAL; + + if (!pr->flags.throttling) + return -ENODEV; + + pr->throttling.state = 0; + local_irq_disable(); + value = acpi_read_throttling_status(&pr->throttling); + if (value >= 0) { + state = acpi_get_throttling_state(pr, value); + pr->throttling.state = state; + } + local_irq_enable(); + + return 0; +} + +static int acpi_processor_get_throttling(struct acpi_processor *pr) +{ + return pr->throttling.acpi_processor_get_throttling(pr); +} + +static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr, + int state) { u32 value = 0; u32 duty_mask = 0; u32 duty_value = 0; - if (!pr) return -EINVAL; @@ -113,6 +429,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) if (state == pr->throttling.state) return 0; + if (state < pr->throttling_platform_limit) + return -EPERM; /* * Calculate the duty_value and duty_mask. */ @@ -165,12 +483,51 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) return 0; } +static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr, + int state) +{ + u32 value = 0; + + if (!pr) + return -EINVAL; + + if ((state < 0) || (state > (pr->throttling.state_count - 1))) + return -EINVAL; + + if (!pr->flags.throttling) + return -ENODEV; + + if (state == pr->throttling.state) + return 0; + + if (state < pr->throttling_platform_limit) + return -EPERM; + + local_irq_disable(); + + value = acpi_get_throttling_value(pr, state); + if (value >= 0) { + acpi_write_throttling_state(&pr->throttling, value); + pr->throttling.state = state; + } + local_irq_enable(); + + return 0; +} + +int acpi_processor_set_throttling(struct acpi_processor *pr, int state) +{ + return pr->throttling.acpi_processor_set_throttling(pr, state); +} + int acpi_processor_get_throttling_info(struct acpi_processor *pr) { int result = 0; int step = 0; int i = 0; - + int no_ptc = 0; + int no_tss = 0; + int no_tsd = 0; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n", @@ -182,6 +539,21 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) return -EINVAL; /* TBD: Support ACPI 2.0 objects */ + no_ptc = acpi_processor_get_throttling_control(pr); + no_tss = acpi_processor_get_throttling_states(pr); + no_tsd = acpi_processor_get_tsd(pr); + + if (no_ptc || no_tss) { + pr->throttling.acpi_processor_get_throttling = + &acpi_processor_get_throttling_fadt; + pr->throttling.acpi_processor_set_throttling = + &acpi_processor_set_throttling_fadt; + } else { + pr->throttling.acpi_processor_get_throttling = + &acpi_processor_get_throttling_ptc; + pr->throttling.acpi_processor_set_throttling = + &acpi_processor_set_throttling_ptc; + } if (!pr->throttling.address) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n")); @@ -262,7 +634,6 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq, int i = 0; int result = 0; - if (!pr) goto end; @@ -280,15 +651,25 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq, } seq_printf(seq, "state count: %d\n" - "active state: T%d\n", - pr->throttling.state_count, pr->throttling.state); + "active state: T%d\n" + "state available: T%d to T%d\n", + pr->throttling.state_count, pr->throttling.state, + pr->throttling_platform_limit, + pr->throttling.state_count - 1); seq_puts(seq, "states:\n"); - for (i = 0; i < pr->throttling.state_count; i++) - seq_printf(seq, " %cT%d: %02d%%\n", - (i == pr->throttling.state ? '*' : ' '), i, - (pr->throttling.states[i].performance ? pr-> - throttling.states[i].performance / 10 : 0)); + if (acpi_processor_get_throttling == acpi_processor_get_throttling_fadt) + for (i = 0; i < pr->throttling.state_count; i++) + seq_printf(seq, " %cT%d: %02d%%\n", + (i == pr->throttling.state ? '*' : ' '), i, + (pr->throttling.states[i].performance ? pr-> + throttling.states[i].performance / 10 : 0)); + else + for (i = 0; i < pr->throttling.state_count; i++) + seq_printf(seq, " %cT%d: %02d%%\n", + (i == pr->throttling.state ? '*' : ' '), i, + (int)pr->throttling.states_tss[i]. + freqpercentage); end: return 0; @@ -301,7 +682,7 @@ static int acpi_processor_throttling_open_fs(struct inode *inode, PDE(inode)->data); } -static ssize_t acpi_processor_write_throttling(struct file * file, +static ssize_t acpi_processor_write_throttling(struct file *file, const char __user * buffer, size_t count, loff_t * data) { @@ -310,7 +691,6 @@ static ssize_t acpi_processor_write_throttling(struct file * file, struct acpi_processor *pr = m->private; char state_string[12] = { '\0' }; - if (!pr || (count > sizeof(state_string) - 1)) return -EINVAL; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index c1bae106833..974d00ccfe8 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -127,7 +127,7 @@ static int acpi_sbs_resume(struct acpi_device *device); static struct acpi_driver acpi_sbs_driver = { .name = "sbs", .class = ACPI_SBS_CLASS, - .ids = ACPI_SBS_HID, + .ids = "ACPI0001,ACPI0005", .ops = { .add = acpi_sbs_add, .remove = acpi_sbs_remove, @@ -176,10 +176,8 @@ struct acpi_battery { }; struct acpi_sbs { - acpi_handle handle; int base; struct acpi_device *device; - struct acpi_ec_smbus *smbus; struct mutex mutex; int sbsm_present; int sbsm_batteries_supported; @@ -511,7 +509,7 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs) "acpi_sbs_read_word() failed")); goto end; } - + sbs->sbsm_present = 1; sbs->sbsm_batteries_supported = battery_system_info & 0x000f; end: @@ -1630,13 +1628,12 @@ static int acpi_sbs_add(struct acpi_device *device) { struct acpi_sbs *sbs = NULL; int result = 0, remove_result = 0; - unsigned long sbs_obj; int id; acpi_status status = AE_OK; unsigned long val; status = - acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val); + acpi_evaluate_integer(device->handle, "_EC", NULL, &val); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC")); return -EIO; @@ -1653,7 +1650,7 @@ static int acpi_sbs_add(struct acpi_device *device) sbs_mutex_lock(sbs); - sbs->base = (val & 0xff00ull) >> 8; + sbs->base = 0xff & (val >> 8); sbs->device = device; strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); @@ -1665,24 +1662,10 @@ static int acpi_sbs_add(struct acpi_device *device) ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed")); goto end; } - status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj); - if (status) { - ACPI_EXCEPTION((AE_INFO, status, - "acpi_evaluate_integer() failed")); - result = -EIO; - goto end; - } - if (sbs_obj > 0) { - result = acpi_sbsm_get_info(sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbsm_get_info() failed")); - goto end; - } - sbs->sbsm_present = 1; - } - if (sbs->sbsm_present == 0) { + acpi_sbsm_get_info(sbs); + + if (!sbs->sbsm_present) { result = acpi_battery_add(sbs, 0); if (result) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, @@ -1702,8 +1685,6 @@ static int acpi_sbs_add(struct acpi_device *device) } } - sbs->handle = device->handle; - init_timer(&sbs->update_timer); result = acpi_check_update_proc(sbs); if (result) diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 42127c0d612..3279e72a94f 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -210,11 +210,6 @@ static void acpi_hibernation_finish(void) /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); - - if (init_8259A_after_S1) { - printk("Broken toshiba laptop -> kicking interrupts\n"); - init_8259A(0); - } } static int acpi_hibernation_pre_restore(void) diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c index 1285e91474f..002bb33003a 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 table_index, u8 flags) * 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 acpi_table_header *table, u32 length) 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 acpi_table_header *table, u32 length) * 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/uteval.c b/drivers/acpi/utilities/uteval.c index 8ec6f8e4813..f112af433e3 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -62,16 +62,13 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, static char *acpi_interfaces_supported[] = { /* Operating System Vendor Strings */ - "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/video.c b/drivers/acpi/video.c index 00d25b34725..5f014d3764c 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -33,6 +33,7 @@ #include <linux/seq_file.h> #include <linux/backlight.h> +#include <linux/video_output.h> #include <asm/uaccess.h> #include <acpi/acpi_bus.h> @@ -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(struct acpi_video_device *device, 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_backlight_ops = { .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 -------------------------------------------------------------------------- */ @@ -531,7 +559,6 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) static void acpi_video_device_find_cap(struct acpi_video_device *device) { - acpi_integer status; acpi_handle h_dummy1; int i; u32 max_level = 0; @@ -565,50 +592,55 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) device->cap._DSS = 1; } - status = acpi_video_device_lcd_query_levels(device, &obj); - - if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) { - int count = 0; - union acpi_object *o; - - br = kzalloc(sizeof(*br), GFP_KERNEL); - if (!br) { - printk(KERN_ERR "can't allocate memory\n"); - } else { - br->levels = kmalloc(obj->package.count * - sizeof *(br->levels), GFP_KERNEL); - if (!br->levels) - goto out; - - for (i = 0; i < obj->package.count; i++) { - o = (union acpi_object *)&obj->package. - elements[i]; - if (o->type != ACPI_TYPE_INTEGER) { - printk(KERN_ERR PREFIX "Invalid data\n"); - continue; - } - br->levels[count] = (u32) o->integer.value; - if (br->levels[count] > max_level) - max_level = br->levels[count]; - count++; - } - out: - if (count < 2) { - kfree(br->levels); - kfree(br); + if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { + + if (obj->package.count >= 2) { + int count = 0; + union acpi_object *o; + + br = kzalloc(sizeof(*br), GFP_KERNEL); + if (!br) { + printk(KERN_ERR "can't allocate memory\n"); } else { - br->count = count; - device->brightness = br; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "found %d brightness levels\n", - count)); + br->levels = kmalloc(obj->package.count * + sizeof *(br->levels), GFP_KERNEL); + if (!br->levels) + goto out; + + for (i = 0; i < obj->package.count; i++) { + o = (union acpi_object *)&obj->package. + elements[i]; + if (o->type != ACPI_TYPE_INTEGER) { + printk(KERN_ERR PREFIX "Invalid data\n"); + continue; + } + br->levels[count] = (u32) o->integer.value; + + if (br->levels[count] > max_level) + max_level = br->levels[count]; + count++; + } + out: + if (count < 2) { + kfree(br->levels); + kfree(br); + } else { + br->count = count; + device->brightness = br; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "found %d brightness levels\n", + count)); + } } } + + } else { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n")); } kfree(obj); - if (device->cap._BCL && device->cap._BCM && device->cap._BQC){ + if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ unsigned long tmp; static int count = 0; char *name; @@ -626,6 +658,17 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) 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 +1712,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) ACPI_DEVICE_NOTIFY, acpi_video_device_notify); backlight_device_unregister(device->backlight); + video_output_unregister(device->output_dev); return 0; } |