aboutsummaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig15
-rw-r--r--drivers/acpi/acpi_memhotplug.c14
-rw-r--r--drivers/acpi/asus_acpi.c129
-rw-r--r--drivers/acpi/battery.c14
-rw-r--r--drivers/acpi/button.c215
-rw-r--r--drivers/acpi/dock.c148
-rw-r--r--drivers/acpi/ec.c1127
-rw-r--r--drivers/acpi/events/evmisc.c15
-rw-r--r--drivers/acpi/events/evrgnini.c13
-rw-r--r--drivers/acpi/executer/exmutex.c6
-rw-r--r--drivers/acpi/glue.c26
-rw-r--r--drivers/acpi/ibm_acpi.c1039
-rw-r--r--drivers/acpi/motherboard.c6
-rw-r--r--drivers/acpi/osl.c24
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/power.c9
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/processor_idle.c111
-rw-r--r--drivers/acpi/processor_perflib.c4
-rw-r--r--drivers/acpi/sbs.c20
-rw-r--r--drivers/acpi/sleep/wakeup.c6
-rw-r--r--drivers/acpi/tables/tbget.c2
-rw-r--r--drivers/acpi/tables/tbrsdt.c2
-rw-r--r--drivers/acpi/toshiba_acpi.c88
-rw-r--r--drivers/acpi/utilities/utdebug.c5
-rw-r--r--drivers/acpi/utilities/utmutex.c16
26 files changed, 1766 insertions, 1292 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 0f9d4be7ed7..b0897a0b206 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -97,6 +97,7 @@ config ACPI_BATTERY
config ACPI_BUTTON
tristate "Button"
+ depends on INPUT
default y
help
This driver handles events on the power, sleep and lid buttons.
@@ -172,6 +173,7 @@ config ACPI_NUMA
config ACPI_ASUS
tristate "ASUS/Medion Laptop Extras"
depends on X86
+ select BACKLIGHT_CLASS_DEVICE
---help---
This driver provides support for extra features of ACPI-compatible
ASUS laptops. As some of Medion laptops are made by ASUS, it may also
@@ -200,6 +202,7 @@ config ACPI_ASUS
config ACPI_IBM
tristate "IBM ThinkPad Laptop Extras"
depends on X86
+ select BACKLIGHT_CLASS_DEVICE
---help---
This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -222,9 +225,21 @@ config ACPI_IBM_DOCK
If you are not sure, say N here.
+config ACPI_IBM_BAY
+ bool "Legacy Removable Bay Support"
+ depends on ACPI_IBM
+ depends on ACPI_BAY=n
+ default n
+ ---help---
+ Allows the ibm_acpi driver to handle removable bays.
+ This support is obsoleted by CONFIG_ACPI_BAY.
+
+ If you are not sure, say N here.
+
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on X86
+ select BACKLIGHT_CLASS_DEVICE
---help---
This driver adds support for access to certain system settings
on "legacy free" Toshiba laptops. These laptops can be recognized by
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 13687835c46..150112ae48e 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -85,6 +85,8 @@ struct acpi_memory_device {
struct list_head res_list;
};
+static int acpi_hotmem_initialized;
+
static acpi_status
acpi_memory_get_resource(struct acpi_resource *resource, void *context)
{
@@ -414,7 +416,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
/* Set the device state */
mem_device->state = MEMORY_POWER_ON_STATE;
- printk(KERN_INFO "%s \n", acpi_device_name(device));
+ printk(KERN_DEBUG "%s \n", acpi_device_name(device));
return result;
}
@@ -438,6 +440,15 @@ static int acpi_memory_device_start (struct acpi_device *device)
struct acpi_memory_device *mem_device;
int result = 0;
+ /*
+ * Early boot code has recognized memory area by EFI/E820.
+ * If DSDT shows these memory devices on boot, hotplug is not necessary
+ * for them. So, it just returns until completion of this driver's
+ * start up.
+ */
+ if (!acpi_hotmem_initialized)
+ return 0;
+
mem_device = acpi_driver_data(device);
if (!acpi_memory_check_device(mem_device)) {
@@ -537,6 +548,7 @@ static int __init acpi_memory_device_init(void)
return -ENODEV;
}
+ acpi_hotmem_initialized = 1;
return 0;
}
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index f7db8ea7ac0..bfae3ffff13 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
+#include <linux/backlight.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
@@ -138,6 +139,7 @@ struct asus_hotk {
S2x, //S200 (J1 reported), Victor MP-XP7210
W1N, //W1000N
W5A, //W5A
+ W3V, //W3030V
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
//(Centrino)
END_MODEL
@@ -376,6 +378,17 @@ static struct model_data model_conf[END_MODEL] = {
.display_get = "\\ADVG"},
{
+ .name = "W3V",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .lcd_status = "\\BKLT",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"},
+
+ {
.name = "xxN",
.mt_mled = "MLED",
/* WLED present, but not controlled by ACPI */
@@ -390,6 +403,8 @@ static struct model_data model_conf[END_MODEL] = {
/* procdir we use */
static struct proc_dir_entry *asus_proc_dir;
+static struct backlight_device *asus_backlight_device;
+
/*
* This header is made available to allow proper configuration given model,
* revision number , ... this info cannot go in struct asus_hotk because it is
@@ -555,11 +570,11 @@ static int
write_led(const char __user * buffer, unsigned long count,
char *ledname, int ledmask, int invert)
{
- int value;
+ int rv, value;
int led_out = 0;
- count = parse_arg(buffer, count, &value);
- if (count > 0)
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0)
led_out = value ? 1 : 0;
hotk->status =
@@ -572,7 +587,7 @@ write_led(const char __user * buffer, unsigned long count,
printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
ledname);
- return count;
+ return rv;
}
/*
@@ -607,20 +622,18 @@ static int
proc_write_ledd(struct file *file, const char __user * buffer,
unsigned long count, void *data)
{
- int value;
+ int rv, value;
- count = parse_arg(buffer, count, &value);
- if (count > 0) {
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0) {
if (!write_acpi_int
(hotk->handle, hotk->methods->mt_ledd, value, NULL))
printk(KERN_WARNING
"Asus ACPI: LED display write failed\n");
else
hotk->ledd_status = (u32) value;
- } else if (count < 0)
- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
-
- return count;
+ }
+ return rv;
}
/*
@@ -761,15 +774,15 @@ static int
proc_write_lcd(struct file *file, const char __user * buffer,
unsigned long count, void *data)
{
- int value;
+ int rv, value;
- count = parse_arg(buffer, count, &value);
- if (count > 0)
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0)
set_lcd_state(value);
- return count;
+ return rv;
}
-static int read_brightness(void)
+static int read_brightness(struct backlight_device *bd)
{
int value;
@@ -791,9 +804,10 @@ static int read_brightness(void)
/*
* Change the brightness level
*/
-static void set_brightness(int value)
+static int set_brightness(int value)
{
acpi_status status = 0;
+ int ret = 0;
/* SPLV laptop */
if (hotk->methods->brightness_set) {
@@ -801,11 +815,12 @@ static void set_brightness(int value)
value, NULL))
printk(KERN_WARNING
"Asus ACPI: Error changing brightness\n");
- return;
+ ret = -EIO;
+ goto out;
}
/* No SPLV method if we are here, act as appropriate */
- value -= read_brightness();
+ value -= read_brightness(NULL);
while (value != 0) {
status = acpi_evaluate_object(NULL, (value > 0) ?
hotk->methods->brightness_up :
@@ -815,33 +830,37 @@ static void set_brightness(int value)
if (ACPI_FAILURE(status))
printk(KERN_WARNING
"Asus ACPI: Error changing brightness\n");
+ ret = -EIO;
}
- return;
+out:
+ return ret;
+}
+
+static int set_brightness_status(struct backlight_device *bd)
+{
+ return set_brightness(bd->props->brightness);
}
static int
proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
- return sprintf(page, "%d\n", read_brightness());
+ return sprintf(page, "%d\n", read_brightness(NULL));
}
static int
proc_write_brn(struct file *file, const char __user * buffer,
unsigned long count, void *data)
{
- int value;
+ int rv, value;
- count = parse_arg(buffer, count, &value);
- if (count > 0) {
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0) {
value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
/* 0 <= value <= 15 */
set_brightness(value);
- } else if (count < 0) {
- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
}
-
- return count;
+ return rv;
}
static void set_display(int value)
@@ -880,15 +899,12 @@ static int
proc_write_disp(struct file *file, const char __user * buffer,
unsigned long count, void *data)
{
- int value;
+ int rv, value;
- count = parse_arg(buffer, count, &value);
- if (count > 0)
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0)
set_display(value);
- else if (count < 0)
- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
-
- return count;
+ return rv;
}
typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
@@ -1097,6 +1113,8 @@ static int asus_model_match(char *model)
return A4G;
else if (strncmp(model, "W1N", 3) == 0)
return W1N;
+ else if (strncmp(model, "W3V", 3) == 0)
+ return W3V;
else if (strncmp(model, "W5A", 3) == 0)
return W5A;
else
@@ -1200,9 +1218,10 @@ static int asus_hotk_get_info(void)
hotk->methods->mt_wled = NULL;
/* L5D's WLED is not controlled by ACPI */
else if (strncmp(string, "M2N", 3) == 0 ||
+ strncmp(string, "W3V", 3) == 0 ||
strncmp(string, "S1N", 3) == 0)
hotk->methods->mt_wled = "WLED";
- /* M2N and S1N have a usable WLED */
+ /* M2N, S1N and W3V have a usable WLED */
else if (asus_info) {
if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
hotk->methods->mled_status = NULL;
@@ -1325,6 +1344,26 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
return 0;
}
+static struct backlight_properties asus_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = read_brightness,
+ .update_status = set_brightness_status,
+ .max_brightness = 15,
+};
+
+static void __exit asus_acpi_exit(void)
+{
+ if (asus_backlight_device)
+ backlight_device_unregister(asus_backlight_device);
+
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ remove_proc_entry(PROC_ASUS, acpi_root_dir);
+
+ kfree(asus_info);
+
+ return;
+}
+
static int __init asus_acpi_init(void)
{
int result;
@@ -1362,17 +1401,15 @@ static int __init asus_acpi_init(void)
return result;
}
- return 0;
-}
-
-static void __exit asus_acpi_exit(void)
-{
- acpi_bus_unregister_driver(&asus_hotk_driver);
- remove_proc_entry(PROC_ASUS, acpi_root_dir);
-
- kfree(asus_info);
+ asus_backlight_device = backlight_device_register("asus", NULL,
+ &asus_backlight_data);
+ if (IS_ERR(asus_backlight_device)) {
+ printk(KERN_ERR "Could not register asus backlight device\n");
+ asus_backlight_device = NULL;
+ asus_acpi_exit();
+ }
- return;
+ return 0;
}
module_init(asus_acpi_init);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index adb0d272573..f47c78a1065 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -64,6 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
static int acpi_battery_add(struct acpi_device *device);
static int acpi_battery_remove(struct acpi_device *device, int type);
+static int acpi_battery_resume(struct acpi_device *device, int status);
static struct acpi_driver acpi_battery_driver = {
.name = ACPI_BATTERY_DRIVER_NAME,
@@ -71,6 +72,7 @@ static struct acpi_driver acpi_battery_driver = {
.ids = ACPI_BATTERY_HID,
.ops = {
.add = acpi_battery_add,
+ .resume = acpi_battery_resume,
.remove = acpi_battery_remove,
},
};
@@ -753,6 +755,18 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
return 0;
}
+/* this is needed to learn about changes made in suspended state */
+static int acpi_battery_resume(struct acpi_device *device, int state)
+{
+ struct acpi_battery *battery;
+
+ if (!device)
+ return -EINVAL;
+
+ battery = device->driver_data;
+ return acpi_battery_check(battery);
+}
+
static int __init acpi_battery_init(void)
{
int result;
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index fe914ebc4bb..ac860583c20 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -29,6 +29,7 @@
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/input.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -62,7 +63,7 @@
#define _COMPONENT ACPI_BUTTON_COMPONENT
ACPI_MODULE_NAME("acpi_button")
- MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
MODULE_LICENSE("GPL");
@@ -78,12 +79,14 @@ static struct acpi_driver acpi_button_driver = {
.ops = {
.add = acpi_button_add,
.remove = acpi_button_remove,
- },
+ },
};
struct acpi_button {
struct acpi_device *device; /* Fixed button kludge */
- u8 type;
+ unsigned int type;
+ struct input_dev *input;
+ char phys[32]; /* for input device */
unsigned long pushed;
};
@@ -111,7 +114,6 @@ static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_button *button = seq->private;
-
if (!button || !button->device)
return 0;
@@ -132,18 +134,13 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
acpi_status status;
unsigned long state;
-
if (!button || !button->device)
return 0;
status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state);
- if (ACPI_FAILURE(status)) {
- seq_printf(seq, "state: unsupported\n");
- } else {
- seq_printf(seq, "state: %s\n",
- (state ? "open" : "closed"));
- }
-
+ seq_printf(seq, "state: %s\n",
+ ACPI_FAILURE(status) ? "unsupported" :
+ (state ? "open" : "closed"));
return 0;
}
@@ -159,8 +156,7 @@ static struct proc_dir_entry *acpi_lid_dir;
static int acpi_button_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- struct acpi_button *button = NULL;
-
+ struct acpi_button *button;
if (!device || !acpi_driver_data(device))
return -EINVAL;
@@ -228,10 +224,8 @@ static int acpi_button_add_fs(struct acpi_device *device)
static int acpi_button_remove_fs(struct acpi_device *device)
{
- struct acpi_button *button = NULL;
-
+ struct acpi_button *button = acpi_driver_data(device);
- button = acpi_driver_data(device);
if (acpi_device_dir(device)) {
if (button->type == ACPI_BUTTON_TYPE_LID)
remove_proc_entry(ACPI_BUTTON_FILE_STATE,
@@ -254,13 +248,33 @@ static int acpi_button_remove_fs(struct acpi_device *device)
static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_button *button = data;
-
+ struct input_dev *input;
if (!button || !button->device)
return;
switch (event) {
case ACPI_BUTTON_NOTIFY_STATUS:
+ input = button->input;
+
+ if (button->type == ACPI_BUTTON_TYPE_LID) {
+ struct acpi_handle *handle = button->device->handle;
+ unsigned long state;
+
+ if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID",
+ NULL, &state)))
+ input_report_switch(input, SW_LID, !state);
+
+ } else {
+ int keycode = test_bit(KEY_SLEEP, input->keybit) ?
+ KEY_SLEEP : KEY_POWER;
+
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ }
+ input_sync(input);
+
acpi_bus_generate_event(button->device, event,
++button->pushed);
break;
@@ -277,7 +291,6 @@ static acpi_status acpi_button_notify_fixed(void *data)
{
struct acpi_button *button = data;
-
if (!button)
return AE_BAD_PARAMETER;
@@ -286,24 +299,75 @@ static acpi_status acpi_button_notify_fixed(void *data)
return AE_OK;
}
-static int acpi_button_add(struct acpi_device *device)
+static int acpi_button_install_notify_handlers(struct acpi_button *button)
{
- int result = 0;
- acpi_status status = AE_OK;
- struct acpi_button *button = NULL;
+ acpi_status status;
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWERF:
+ status =
+ acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+ acpi_button_notify_fixed,
+ button);
+ break;
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ status =
+ acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+ acpi_button_notify_fixed,
+ button);
+ break;
+ default:
+ status = acpi_install_notify_handler(button->device->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_button_notify,
+ button);
+ break;
+ }
+
+ return ACPI_FAILURE(status) ? -ENODEV : 0;
+}
+
+static void acpi_button_remove_notify_handlers(struct acpi_button *button)
+{
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWERF:
+ acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+ acpi_button_notify_fixed);
+ break;
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+ acpi_button_notify_fixed);
+ break;
+ default:
+ acpi_remove_notify_handler(button->device->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_button_notify);
+ break;
+ }
+}
+
+static int acpi_button_add(struct acpi_device *device)
+{
+ int error;
+ struct acpi_button *button;
+ struct input_dev *input;
if (!device)
return -EINVAL;
- button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
+ button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
if (!button)
return -ENOMEM;
- memset(button, 0, sizeof(struct acpi_button));
button->device = device;
acpi_driver_data(device) = button;
+ button->input = input = input_allocate_device();
+ if (!input) {
+ error = -ENOMEM;
+ goto err_free_button;
+ }
+
/*
* Determine the button type (via hid), as fixed-feature buttons
* need to be handled a bit differently than generic-space.
@@ -338,39 +402,48 @@ static int acpi_button_add(struct acpi_device *device)
} else {
printk(KERN_ERR PREFIX "Unsupported hid [%s]\n",
acpi_device_hid(device));
- result = -ENODEV;
- goto end;
+ error = -ENODEV;
+ goto err_free_input;
}
- result = acpi_button_add_fs(device);
- if (result)
- goto end;
+ error = acpi_button_add_fs(device);
+ if (error)
+ goto err_free_input;
+
+ error = acpi_button_install_notify_handlers(button);
+ if (error)
+ goto err_remove_fs;
+
+ snprintf(button->phys, sizeof(button->phys),
+ "%s/button/input0", acpi_device_hid(device));
+
+ input->name = acpi_device_name(device);
+ input->phys = button->phys;
+ input->id.bustype = BUS_HOST;
+ input->id.product = button->type;
switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWER:
case ACPI_BUTTON_TYPE_POWERF:
- status =
- acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
- acpi_button_notify_fixed,
- button);
+ input->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_POWER, input->keybit);
break;
+
+ case ACPI_BUTTON_TYPE_SLEEP:
case ACPI_BUTTON_TYPE_SLEEPF:
- status =
- acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
- acpi_button_notify_fixed,
- button);
+ input->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_SLEEP, input->keybit);
break;
- default:
- status = acpi_install_notify_handler(device->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_button_notify,
- button);
+
+ case ACPI_BUTTON_TYPE_LID:
+ input->evbit[0] = BIT(EV_SW);
+ set_bit(SW_LID, input->swbit);
break;
}
- if (ACPI_FAILURE(status)) {
- result = -ENODEV;
- goto end;
- }
+ error = input_register_device(input);
+ if (error)
+ goto err_remove_handlers;
if (device->wakeup.flags.valid) {
/* Button's GPE is run-wake GPE */
@@ -385,47 +458,31 @@ static int acpi_button_add(struct acpi_device *device)
printk(KERN_INFO PREFIX "%s [%s]\n",
acpi_device_name(device), acpi_device_bid(device));
- end:
- if (result) {
- acpi_button_remove_fs(device);
- kfree(button);
- }
+ return 0;
- return result;
+ err_remove_handlers:
+ acpi_button_remove_notify_handlers(button);
+ err_remove_fs:
+ acpi_button_remove_fs(device);
+ err_free_input:
+ input_free_device(input);
+ err_free_button:
+ kfree(button);
+ return error;
}
static int acpi_button_remove(struct acpi_device *device, int type)
{
- acpi_status status = 0;
- struct acpi_button *button = NULL;
-
+ struct acpi_button *button;
if (!device || !acpi_driver_data(device))
return -EINVAL;
button = acpi_driver_data(device);
- /* Unregister for device notifications. */
- switch (button->type) {
- case ACPI_BUTTON_TYPE_POWERF:
- status =
- acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
- acpi_button_notify_fixed);
- break;
- case ACPI_BUTTON_TYPE_SLEEPF:
- status =
- acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
- acpi_button_notify_fixed);
- break;
- default:
- status = acpi_remove_notify_handler(device->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_button_notify);
- break;
- }
-
+ acpi_button_remove_notify_handlers(button);
acpi_button_remove_fs(device);
-
+ input_unregister_device(button->input);
kfree(button);
return 0;
@@ -433,8 +490,7 @@ static int acpi_button_remove(struct acpi_device *device, int type)
static int __init acpi_button_init(void)
{
- int result = 0;
-
+ int result;
acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
if (!acpi_button_dir)
@@ -451,7 +507,6 @@ static int __init acpi_button_init(void)
static void __exit acpi_button_exit(void)
{
-
acpi_bus_unregister_driver(&acpi_button_driver);
if (acpi_power_dir)
@@ -461,8 +516,6 @@ static void __exit acpi_button_exit(void)
if (acpi_lid_dir)
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
-
- return;
}
module_init(acpi_button_init);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 3c3dee844df..90990a4b652 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -27,6 +27,8 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -38,13 +40,15 @@ MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME);
MODULE_LICENSE("GPL");
static struct atomic_notifier_head dock_notifier_list;
+static struct platform_device dock_device;
+static char dock_device_name[] = "dock";
struct dock_station {
acpi_handle handle;
unsigned long last_dock_time;
u32 flags;
spinlock_t dd_lock;
- spinlock_t hp_lock;
+ struct mutex hp_lock;
struct list_head dependent_devices;
struct list_head hotplug_devices;
};
@@ -114,9 +118,9 @@ static void
dock_add_hotplug_device(struct dock_station *ds,
struct dock_dependent_device *dd)
{
- spin_lock(&ds->hp_lock);
+ mutex_lock(&ds->hp_lock);
list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
- spin_unlock(&ds->hp_lock);
+ mutex_unlock(&ds->hp_lock);
}
/**
@@ -130,9 +134,9 @@ static void
dock_del_hotplug_device(struct dock_station *ds,
struct dock_dependent_device *dd)
{
- spin_lock(&ds->hp_lock);
+ mutex_lock(&ds->hp_lock);
list_del(&dd->hotplug_list);
- spin_unlock(&ds->hp_lock);
+ mutex_unlock(&ds->hp_lock);
}
/**
@@ -295,7 +299,7 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
{
struct dock_dependent_device *dd;
- spin_lock(&ds->hp_lock);
+ mutex_lock(&ds->hp_lock);
/*
* First call driver specific hotplug functions
@@ -317,15 +321,17 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
else
dock_create_acpi_device(dd->handle);
}
- spin_unlock(&ds->hp_lock);
+ mutex_unlock(&ds->hp_lock);
}
static void dock_event(struct dock_station *ds, u32 event, int num)
{
+ struct device *dev = &dock_device.dev;
/*
- * we don't do events until someone tells me that
- * they would like to have them.
+ * Indicate that the status of the dock station has
+ * changed.
*/
+ kobject_uevent(&dev->kobj, KOBJ_CHANGE);
}
/**
@@ -440,6 +446,9 @@ static int dock_in_progress(struct dock_station *ds)
*/
int register_dock_notifier(struct notifier_block *nb)
{
+ if (!dock_station)
+ return -ENODEV;
+
return atomic_notifier_chain_register(&dock_notifier_list, nb);
}
@@ -451,6 +460,9 @@ EXPORT_SYMBOL_GPL(register_dock_notifier);
*/
void unregister_dock_notifier(struct notifier_block *nb)
{
+ if (!dock_station)
+ return;
+
atomic_notifier_chain_unregister(&dock_notifier_list, nb);
}
@@ -511,6 +523,37 @@ void unregister_hotplug_dock_device(acpi_handle handle)
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
/**
+ * handle_eject_request - handle an undock request checking for error conditions
+ *
+ * Check to make sure the dock device is still present, then undock and
+ * hotremove all the devices that may need removing.
+ */
+static int handle_eject_request(struct dock_station *ds, u32 event)
+{
+ if (!dock_present(ds))
+ return -ENODEV;
+
+ if (dock_in_progress(ds))
+ return -EBUSY;
+
+ /*
+ * here we need to generate the undock
+ * event prior to actually doing the undock
+ * so that the device struct still exists.
+ */
+ dock_event(ds, event, UNDOCK_EVENT);
+ hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
+ undock(ds);
+ eject_dock(ds);
+ if (dock_present(ds)) {
+ printk(KERN_ERR PREFIX "Unable to undock!\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/**
* dock_notify - act upon an acpi dock notification
* @handle: the dock station handle
* @event: the acpi event
@@ -518,9 +561,7 @@ EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
*
* If we are notified to dock, then check to see if the dock is
* present and then dock. Notify all drivers of the dock event,
- * and then hotplug and devices that may need hotplugging. For undock
- * check to make sure the dock device is still present, then undock
- * and hotremove all the devices that may need removing.
+ * and then hotplug and devices that may need hotplugging.
*/
static void dock_notify(acpi_handle handle, u32 event, void *data)
{
@@ -552,19 +593,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
* to the driver who wish to hotplug.
*/
case ACPI_NOTIFY_EJECT_REQUEST:
- if (!dock_in_progress(ds) && dock_present(ds)) {
- /*
- * here we need to generate the undock
- * event prior to actually doing the undock
- * so that the device struct still exists.
- */
- dock_event(ds, event, UNDOCK_EVENT);
- hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
- undock(ds);
- eject_dock(ds);
- if (dock_present(ds))
- printk(KERN_ERR PREFIX "Unable to undock!\n");
- }
+ handle_eject_request(ds, event);
break;
default:
printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -603,6 +632,33 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
+/*
+ * show_docked - read method for "docked" file in sysfs
+ */
+static ssize_t show_docked(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
+
+}
+DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
+
+/*
+ * write_undock - write method for "undock" file in sysfs
+ */
+static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ if (!count)
+ return -EINVAL;
+
+ ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
+ return ret ? ret: count;
+}
+DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
+
/**
* dock_add - add a new dock station
* @handle: the dock station handle
@@ -625,9 +681,33 @@ static int dock_add(acpi_handle handle)
INIT_LIST_HEAD(&dock_station->dependent_devices);
INIT_LIST_HEAD(&dock_station->hotplug_devices);
spin_lock_init(&dock_station->dd_lock);
- spin_lock_init(&dock_station->hp_lock);
+ mutex_init(&dock_station->hp_lock);
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
+ /* initialize platform device stuff */
+ dock_device.name = dock_device_name;
+ ret = platform_device_register(&dock_device);
+ if (ret) {
+ printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
+ kfree(dock_station);
+ return ret;
+ }
+ ret = device_create_file(&dock_device.dev, &dev_attr_docked);
+ if (ret) {
+ printk("Error %d adding sysfs file\n", ret);
+ platform_device_unregister(&dock_device);
+ kfree(dock_station);
+ return ret;
+ }
+ ret = device_create_file(&dock_device.dev, &dev_attr_undock);
+ if (ret) {
+ printk("Error %d adding sysfs file\n", ret);
+ device_remove_file(&dock_device.dev, &dev_attr_docked);
+ platform_device_unregister(&dock_device);
+ kfree(dock_station);
+ return ret;
+ }
+
/* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_dock_devices, dock_station,
@@ -637,7 +717,8 @@ static int dock_add(acpi_handle handle)
dd = alloc_dock_dependent_device(handle);
if (!dd) {
kfree(dock_station);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto dock_add_err_unregister;
}
add_dock_dependent_device(dock_station, dd);
@@ -657,8 +738,12 @@ static int dock_add(acpi_handle handle)
return 0;
dock_add_err:
- kfree(dock_station);
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);
+ kfree(dock_station);
return ret;
}
@@ -685,6 +770,11 @@ static int dock_remove(void)
if (ACPI_FAILURE(status))
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);
+
/* free dock station memory */
kfree(dock_station);
return 0;
@@ -725,7 +815,7 @@ static int __init dock_init(void)
ACPI_UINT32_MAX, find_dock, &num, NULL);
if (!num)
- return -ENODEV;
+ printk(KERN_INFO "No dock devices found.\n");
return 0;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index d560b5e8dd3..4a909bfb805 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -45,205 +45,127 @@ ACPI_MODULE_NAME("acpi_ec")
#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver"
#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 */
-#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */
-#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
-#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */
+/* EC commands */
+enum ec_command {
+ ACPI_EC_COMMAND_READ = 0x80,
+ ACPI_EC_COMMAND_WRITE = 0x81,
+ ACPI_EC_BURST_ENABLE = 0x82,
+ ACPI_EC_BURST_DISABLE = 0x83,
+ ACPI_EC_COMMAND_QUERY = 0x84,
+};
+/* EC events */
+enum ec_event {
+ ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
+ ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
+};
+
+#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
-#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
-#define ACPI_EC_COMMAND_READ 0x80
-#define ACPI_EC_COMMAND_WRITE 0x81
-#define ACPI_EC_BURST_ENABLE 0x82
-#define ACPI_EC_BURST_DISABLE 0x83
-#define ACPI_EC_COMMAND_QUERY 0x84
-#define EC_POLL 0xFF
-#define EC_INTR 0x00
+
+static enum ec_mode {
+ EC_INTR = 1, /* Output buffer full */
+ EC_POLL, /* Input buffer empty */
+} acpi_ec_mode = EC_INTR;
+
static int acpi_ec_remove(struct acpi_device *device, int type);
static int acpi_ec_start(struct acpi_device *device);
static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_intr_add(struct acpi_device *device);
-static int acpi_ec_poll_add(struct acpi_device *device);
+static int acpi_ec_add(struct acpi_device *device);
static struct acpi_driver acpi_ec_driver = {
.name = ACPI_EC_DRIVER_NAME,
.class = ACPI_EC_CLASS,
.ids = ACPI_EC_HID,
.ops = {
- .add = acpi_ec_intr_add,
+ .add = acpi_ec_add,
.remove = acpi_ec_remove,
.start = acpi_ec_start,
.stop = acpi_ec_stop,
},
};
-union acpi_ec {
- struct {
- u32 mode;
- acpi_handle handle;
- unsigned long uid;
- unsigned long gpe_bit;
- struct acpi_generic_address status_addr;
- struct acpi_generic_address command_addr;
- struct acpi_generic_address data_addr;
- unsigned long global_lock;
- } common;
-
- struct {
- u32 mode;
- acpi_handle handle;
- unsigned long uid;
- unsigned long gpe_bit;
- struct acpi_generic_address status_addr;
- struct acpi_generic_address command_addr;
- struct acpi_generic_address data_addr;
- unsigned long global_lock;
- unsigned int expect_event;
- atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
- atomic_t pending_gpe;
- struct semaphore sem;
- wait_queue_head_t wait;
- } intr;
-
- struct {
- u32 mode;
- acpi_handle handle;
- unsigned long uid;
- unsigned long gpe_bit;
- struct acpi_generic_address status_addr;
- struct acpi_generic_address command_addr;
- struct acpi_generic_address data_addr;
- unsigned long global_lock;
- struct semaphore sem;
- } poll;
-};
-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event);
-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event);
-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data);
-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data);
-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data);
-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data);
-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data);
-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data);
-static void acpi_ec_gpe_poll_query(void *ec_cxt);
-static void acpi_ec_gpe_intr_query(void *ec_cxt);
-static u32 acpi_ec_gpe_poll_handler(void *data);
-static u32 acpi_ec_gpe_intr_handler(void *data);
-static acpi_status __init
-acpi_fake_ecdt_poll_callback(acpi_handle handle,
- u32 Level, void *context, void **retval);
-
-static acpi_status __init
-acpi_fake_ecdt_intr_callback(acpi_handle handle,
- u32 Level, void *context, void **retval);
-
-static int __init acpi_ec_poll_get_real_ecdt(void);
-static int __init acpi_ec_intr_get_real_ecdt(void);
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
-static union acpi_ec *ec_ecdt;
+struct acpi_ec {
+ acpi_handle handle;
+ unsigned long uid;
+ unsigned long gpe;
+ unsigned long command_addr;
+ unsigned long data_addr;
+ unsigned long global_lock;
+ struct mutex lock;
+ atomic_t query_pending;
+ atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
+ wait_queue_head_t wait;
+} *ec_ecdt;
/* External interfaces use first EC only, so remember */
static struct acpi_device *first_ec;
-static int acpi_ec_poll_mode = EC_INTR;
/* --------------------------------------------------------------------------
Transaction Management
-------------------------------------------------------------------------- */
-static u32 acpi_ec_read_status(union acpi_ec *ec)
+static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
{
- u32 status = 0;
-
- acpi_hw_low_level_read(8, &status, &ec->common.status_addr);
- return status;
+ return inb(ec->command_addr);
}
-static int acpi_ec_wait(union acpi_ec *ec, u8 event)
+static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_wait(ec, event);
- else
- return acpi_ec_intr_wait(ec, event);
+ return inb(ec->data_addr);
}
-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event)
+static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
{
- u32 acpi_ec_status = 0;
- u32 i = ACPI_EC_UDELAY_COUNT;
+ outb(command, ec->command_addr);
+}
- if (!ec)
- return -EINVAL;
+static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
+{
+ outb(data, ec->data_addr);
+}
- /* Poll the EC status register waiting for the event to occur. */
- switch (event) {
- case ACPI_EC_EVENT_OBF:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status,
- &ec->common.status_addr);
- if (acpi_ec_status & ACPI_EC_FLAG_OBF)
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i > 0);
- break;
- case ACPI_EC_EVENT_IBE:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status,
- &ec->common.status_addr);
- if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i > 0);
- break;
- default:
- return -EINVAL;
+static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
+{
+ u8 status = acpi_ec_read_status(ec);
+
+ if (event == ACPI_EC_EVENT_OBF_1) {
+ if (status & ACPI_EC_FLAG_OBF)
+ return 1;
+ } else if (event == ACPI_EC_EVENT_IBF_0) {
+ if (!(status & ACPI_EC_FLAG_IBF))
+ return 1;
}
- return -ETIME;
+ return 0;
}
-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
-{
- int result = 0;
-
- ec->intr.expect_event = event;
- smp_mb();
-
- switch (event) {
- case ACPI_EC_EVENT_IBE:
- if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) {
- ec->intr.expect_event = 0;
- return 0;
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event)
+{
+ if (acpi_ec_mode == EC_POLL) {
+ unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+ while (time_before(jiffies, delay)) {
+ if (acpi_ec_check_status(ec, event))
+ return 0;
}
- break;
- default:
- break;
- }
-
- result = wait_event_timeout(ec->intr.wait,
- !ec->intr.expect_event,
- msecs_to_jiffies(ACPI_EC_DELAY));
-
- ec->intr.expect_event = 0;
- smp_mb();
-
- /*
- * Verify that the event in question has actually happened by
- * querying EC status. Do the check even if operation timed-out
- * to make sure that we did not miss interrupt.
- */
- switch (event) {
- case ACPI_EC_EVENT_OBF:
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
- return 0;
- break;
-
- case ACPI_EC_EVENT_IBE:
- if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
+ } else {
+ if (wait_event_timeout(ec->wait,
+ acpi_ec_check_status(ec, event),
+ msecs_to_jiffies(ACPI_EC_DELAY)) ||
+ acpi_ec_check_status(ec, event)) {
return 0;
- break;
+ } else {
+ printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
+ " status = %d, expect_event = %d\n",
+ acpi_ec_read_status(ec), event);
+ }
}
return -ETIME;
@@ -254,262 +176,153 @@ static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
* Note: samsung nv5000 doesn't work with ec burst mode.
* http://bugzilla.kernel.org/show_bug.cgi?id=4980
*/
-int acpi_ec_enter_burst_mode(union acpi_ec *ec)
+int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
{
- u32 tmp = 0;
- int status = 0;
-
+ u8 tmp = 0;
+ u8 status = 0;
status = acpi_ec_read_status(ec);
if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
if (status)
goto end;
- acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE,
- &ec->common.command_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
+ acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+ tmp = acpi_ec_read_data(ec);
if (tmp != 0x90) { /* Burst ACK byte */
return -EINVAL;
}
}
- atomic_set(&ec->intr.leaving_burst, 0);
+ atomic_set(&ec->leaving_burst, 0);
return 0;
end:
- ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode");
+ ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
return -1;
}
-int acpi_ec_leave_burst_mode(union acpi_ec *ec)
+int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
{
- int status = 0;
-
+ u8 status = 0;
status = acpi_ec_read_status(ec);
- if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){
- status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
- if(status)
+ if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) {
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ if (status)
goto end;
- acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr);
- acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
- }
- atomic_set(&ec->intr.leaving_burst, 1);
+ acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
+ acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ }
+ atomic_set(&ec->leaving_burst, 1);
return 0;
-end:
- ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode");
+ end:
+ ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
return -1;
}
-#endif /* ACPI_FUTURE_USAGE */
+#endif /* ACPI_FUTURE_USAGE */
-static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data)
-{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_read(ec, address, data);
- else
- return acpi_ec_intr_read(ec, address, data);
-}
-static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data)
+static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
+ const u8 * wdata, unsigned wdata_len,
+ u8 * rdata, unsigned rdata_len)
{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_write(ec, address, data);
- else
- return acpi_ec_intr_write(ec, address, data);
-}
-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
-{
- acpi_status status = AE_OK;
int result = 0;
- u32 glk = 0;
+ acpi_ec_write_cmd(ec, command);
- if (!ec || !data)
- return -EINVAL;
-
- *data = 0;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ for (; wdata_len > 0; --wdata_len) {
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ if (result) {
+ printk(KERN_ERR PREFIX
+ "write_cmd timeout, command = %d\n", command);
+ goto end;
+ }
+ acpi_ec_write_data(ec, *(wdata++));
}
- if (down_interruptible(&ec->poll.sem)) {
- result = -ERESTARTSYS;
- goto end_nosem;
+ if (!rdata_len) {
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ if (result) {
+ printk(KERN_ERR PREFIX
+ "finish-write timeout, command = %d\n", command);
+ goto end;
+ }
+ } else if (command == ACPI_EC_COMMAND_QUERY) {
+ atomic_set(&ec->query_pending, 0);
}
-
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
- &ec->common.command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
- goto end;
-
- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (result)
- goto end;
-
- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
- *data, address));
-
- end:
- up(&ec->poll.sem);
-end_nosem:
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
-
- return result;
-}
-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
-{
- int result = 0;
- acpi_status status = AE_OK;
- u32 glk = 0;
-
-
- if (!ec)
- return -EINVAL;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- }
+ for (; rdata_len > 0; --rdata_len) {
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+ if (result) {
+ printk(KERN_ERR PREFIX "read timeout, command = %d\n",
+ command);
+ goto end;
+ }
- if (down_interruptible(&ec->poll.sem)) {
- result = -ERESTARTSYS;
- goto end_nosem;
+ *(rdata++) = acpi_ec_read_data(ec);
}
-
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
- &ec->common.command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
- goto end;
-
- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
- goto end;
-
- acpi_hw_low_level_write(8, data, &ec->common.data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
- goto end;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
- data, address));
-
end:
- up(&ec->poll.sem);
-end_nosem:
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
-
return result;
}
-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
+static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
+ const u8 * wdata, unsigned wdata_len,
+ u8 * rdata, unsigned rdata_len)
{
- int status = 0;
+ int status;
u32 glk;
-
- if (!ec || !data)
+ if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
return -EINVAL;
- *data = 0;
+ if (rdata)
+ memset(rdata, 0, rdata_len);
- if (ec->common.global_lock) {
+ mutex_lock(&ec->lock);
+ if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
return -ENODEV;
}
- WARN_ON(in_interrupt());
- down(&ec->intr.sem);
+ /* Make sure GPE is enabled before doing transaction */
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
if (status) {
- printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
+ printk(KERN_DEBUG PREFIX
+ "input buffer is not empty, aborting transaction\n");
goto end;
}
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
- &ec->common.command_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
- }
- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (status) {
- printk(KERN_DEBUG PREFIX "read EC, OB not full\n");
- goto end;
- }
- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
- *data, address));
+ status = acpi_ec_transaction_unlocked(ec, command,
+ wdata, wdata_len,
+ rdata, rdata_len);
end:
- up(&ec->intr.sem);
- if (ec->common.global_lock)
+ if (ec->global_lock)
acpi_release_global_lock(glk);
+ mutex_unlock(&ec->lock);
return status;
}
-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
+static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
{
- int status = 0;
- u32 glk;
-
-
- if (!ec)
- return -EINVAL;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- }
-
- WARN_ON(in_interrupt());
- down(&ec->intr.sem);
-
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
- }
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
- &ec->common.command_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
- }
-
- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
- }
-
- acpi_hw_low_level_write(8, data, &ec->common.data_addr);
+ int result;
+ u8 d;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
- data, address));
-
- up(&ec->intr.sem);
-
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
+ result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
+ &address, 1, &d, 1);
+ *data = d;
+ return result;
+}
- return status;
+static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
+{
+ u8 wdata[2] = { address, data };
+ return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
+ wdata, 2, NULL, 0);
}
/*
@@ -517,9 +330,9 @@ static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
*/
int ec_read(u8 addr, u8 * val)
{
- union acpi_ec *ec;
+ struct acpi_ec *ec;
int err;
- u32 temp_data;
+ u8 temp_data;
if (!first_ec)
return -ENODEV;
@@ -539,7 +352,7 @@ EXPORT_SYMBOL(ec_read);
int ec_write(u8 addr, u8 val)
{
- union acpi_ec *ec;
+ struct acpi_ec *ec;
int err;
if (!first_ec)
@@ -554,255 +367,86 @@ int ec_write(u8 addr, u8 val)
EXPORT_SYMBOL(ec_write);
-static int acpi_ec_query(union acpi_ec *ec, u32 * data)
-{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_query(ec, data);
- else
- return acpi_ec_intr_query(ec, data);
-}
-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
+int ec_transaction(u8 command,
+ const u8 * wdata, unsigned wdata_len,
+ u8 * rdata, unsigned rdata_len)
{
- int result = 0;
- acpi_status status = AE_OK;
- u32 glk = 0;
+ struct acpi_ec *ec;
+ if (!first_ec)
+ return -ENODEV;
- if (!ec || !data)
- return -EINVAL;
-
- *data = 0;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- }
-
- /*
- * Query the EC to find out which _Qxx method we need to evaluate.
- * Note that successful completion of the query causes the ACPI_EC_SCI
- * bit to be cleared (and thus clearing the interrupt source).
- */
- if (down_interruptible(&ec->poll.sem)) {
- result = -ERESTARTSYS;
- goto end_nosem;
- }
-
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
- &ec->common.command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (result)
- goto end;
+ ec = acpi_driver_data(first_ec);
- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
- if (!*data)
- result = -ENODATA;
+ return acpi_ec_transaction(ec, command, wdata,
+ wdata_len, rdata, rdata_len);
+}
- end:
- up(&ec->poll.sem);
-end_nosem:
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
+EXPORT_SYMBOL(ec_transaction);
- return result;
-}
-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
+static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
{
- int status = 0;
- u32 glk;
-
+ int result;
+ u8 d;
if (!ec || !data)
return -EINVAL;
- *data = 0;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- }
-
- down(&ec->intr.sem);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "query EC, IB not empty\n");
- goto end;
- }
/*
* Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
- &ec->common.command_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (status) {
- printk(KERN_DEBUG PREFIX "query EC, OB not full\n");
- goto end;
- }
- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
- if (!*data)
- status = -ENODATA;
+ result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
+ if (result)
+ return result;
- end:
- up(&ec->intr.sem);
+ if (!d)
+ return -ENODATA;
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
-
- return status;
+ *data = d;
+ return 0;
}
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
-union acpi_ec_query_data {
- acpi_handle handle;
- u8 data;
-};
-
static void acpi_ec_gpe_query(void *ec_cxt)
{
- if (acpi_ec_poll_mode)
- acpi_ec_gpe_poll_query(ec_cxt);
- else
- acpi_ec_gpe_intr_query(ec_cxt);
-}
-
-static void acpi_ec_gpe_poll_query(void *ec_cxt)
-{
- union acpi_ec *ec = (union acpi_ec *)ec_cxt;
- u32 value = 0;
- static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
- const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
+ struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+ u8 value = 0;
+ char object_name[8];
-
- if (!ec_cxt)
- goto end;
-
- if (down_interruptible (&ec->poll.sem)) {
+ if (!ec || acpi_ec_query(ec, &value))
return;
- }
- acpi_hw_low_level_read(8, &value, &ec->common.command_addr);
- up(&ec->poll.sem);
-
- /* TBD: Implement asynch events!
- * NOTE: All we care about are EC-SCI's. Other EC events are
- * handled via polling (yuck!). This is because some systems
- * treat EC-SCIs as level (versus EDGE!) triggered, preventing
- * a purely interrupt-driven approach (grumble, grumble).
- */
- if (!(value & ACPI_EC_FLAG_SCI))
- goto end;
-
- if (acpi_ec_query(ec, &value))
- goto end;
-
- object_name[2] = hex[((value >> 4) & 0x0F)];
- object_name[3] = hex[(value & 0x0F)];
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
-
- acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
-
- end:
- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
-}
-static void acpi_ec_gpe_intr_query(void *ec_cxt)
-{
- union acpi_ec *ec = ec_cxt;
- u32 value;
- int result = -ENODATA;
- static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
- const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
-
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
- result = acpi_ec_query(ec, &value);
-
- if (result)
- goto end;
+ snprintf(object_name, 8, "_Q%2.2X", value);
- object_name[2] = hex[((value >> 4) & 0x0F)];
- object_name[3] = hex[(value & 0x0F)];
+ printk(KERN_INFO PREFIX "evaluating %s\n", object_name);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
-
- acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
- end:
- atomic_dec(&ec->intr.pending_gpe);
- return;
+ acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
}
static u32 acpi_ec_gpe_handler(void *data)
{
- if (acpi_ec_poll_mode)
- return acpi_ec_gpe_poll_handler(data);
- else
- return acpi_ec_gpe_intr_handler(data);
-}
-static u32 acpi_ec_gpe_poll_handler(void *data)
-{
acpi_status status = AE_OK;
- union acpi_ec *ec = data;
+ u8 value;
+ struct acpi_ec *ec = (struct acpi_ec *)data;
- if (!ec)
- return ACPI_INTERRUPT_NOT_HANDLED;
-
- acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
-
- status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec);
-
- if (status == AE_OK)
- return ACPI_INTERRUPT_HANDLED;
- else
- return ACPI_INTERRUPT_NOT_HANDLED;
-}
-static u32 acpi_ec_gpe_intr_handler(void *data)
-{
- acpi_status status = AE_OK;
- u32 value;
- union acpi_ec *ec = data;
-
- if (!ec)
- return ACPI_INTERRUPT_NOT_HANDLED;
+ if (acpi_ec_mode == EC_INTR) {
+ wake_up(&ec->wait);
+ }
- acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
value = acpi_ec_read_status(ec);
-
- switch (ec->intr.expect_event) {
- case ACPI_EC_EVENT_OBF:
- if (!(value & ACPI_EC_FLAG_OBF))
- break;
- ec->intr.expect_event = 0;
- wake_up(&ec->intr.wait);
- break;
- case ACPI_EC_EVENT_IBE:
- if ((value & ACPI_EC_FLAG_IBF))
- break;
- ec->intr.expect_event = 0;
- wake_up(&ec->intr.wait);
- break;
- default:
- break;
+ 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);
}
- if (value & ACPI_EC_FLAG_SCI) {
- atomic_add(1, &ec->intr.pending_gpe);
- status = acpi_os_execute(OSL_EC_BURST_HANDLER,
- acpi_ec_gpe_query, ec);
- return status == AE_OK ?
- ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
- }
- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
return status == AE_OK ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
@@ -833,28 +477,25 @@ acpi_ec_space_handler(u32 function,
void *handler_context, void *region_context)
{
int result = 0;
- union acpi_ec *ec = NULL;
+ struct acpi_ec *ec = NULL;
u64 temp = *value;
acpi_integer f_v = 0;
int i = 0;
-
if ((address > 0xFF) || !value || !handler_context)
return AE_BAD_PARAMETER;
if (bit_width != 8 && acpi_strict) {
- printk(KERN_WARNING PREFIX
- "acpi_ec_space_handler: bit_width should be 8\n");
return AE_BAD_PARAMETER;
}
- ec = handler_context;
+ ec = (struct acpi_ec *)handler_context;
next_byte:
switch (function) {
case ACPI_READ:
temp = 0;
- result = acpi_ec_read(ec, (u8) address, (u32 *) & temp);
+ result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
break;
case ACPI_WRITE:
result = acpi_ec_write(ec, (u8) address, (u8) temp);
@@ -905,20 +546,17 @@ static struct proc_dir_entry *acpi_ec_dir;
static int acpi_ec_read_info(struct seq_file *seq, void *offset)
{
- union acpi_ec *ec = seq->private;
-
+ struct acpi_ec *ec = (struct acpi_ec *)seq->private;
if (!ec)
goto end;
- seq_printf(seq, "gpe bit: 0x%02x\n",
- (u32) ec->common.gpe_bit);
+ seq_printf(seq, "gpe: 0x%02x\n", (u32) ec->gpe);
seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
- (u32) ec->common.status_addr.address,
- (u32) ec->common.data_addr.address);
+ (u32) ec->command_addr, (u32) ec->data_addr);
seq_printf(seq, "use global lock: %s\n",
- ec->common.global_lock ? "yes" : "no");
- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+ ec->global_lock ? "yes" : "no");
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
end:
return 0;
@@ -929,7 +567,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_ec_read_info, PDE(inode)->data);
}
-static const struct file_operations acpi_ec_info_ops = {
+static struct file_operations acpi_ec_info_ops = {
.open = acpi_ec_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -941,7 +579,6 @@ static int acpi_ec_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
-
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_ec_dir);
@@ -978,101 +615,34 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
Driver Interface
-------------------------------------------------------------------------- */
-static int acpi_ec_poll_add(struct acpi_device *device)
+static int acpi_ec_add(struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
- union acpi_ec *ec = NULL;
-
+ struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
- ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+ ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec)
return -ENOMEM;
- memset(ec, 0, sizeof(union acpi_ec));
-
- ec->common.handle = device->handle;
- ec->common.uid = -1;
- init_MUTEX(&ec->poll.sem);
- strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_EC_CLASS);
- acpi_driver_data(device) = ec;
-
- /* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
- &ec->common.global_lock);
-
- /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
- http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
- if (ec_ecdt) {
- acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler);
-
- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
- &acpi_ec_gpe_handler);
-
- kfree(ec_ecdt);
- }
-
- /* Get GPE bit assignment (EC events). */
- /* TODO: Add support for _GPE returning a package */
- status =
- acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
- &ec->common.gpe_bit);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit"));
- result = -ENODEV;
- goto end;
+ memset(ec, 0, sizeof(struct acpi_ec));
+
+ ec->handle = device->handle;
+ ec->uid = -1;
+ mutex_init(&ec->lock);
+ atomic_set(&ec->query_pending, 0);
+ if (acpi_ec_mode == EC_INTR) {
+ atomic_set(&ec->leaving_burst, 1);
+ init_waitqueue_head(&ec->wait);
}
-
- result = acpi_ec_add_fs(device);
- if (result)
- goto end;
-
- printk(KERN_INFO PREFIX "%s [%s] (gpe %d) polling mode.\n",
- acpi_device_name(device), acpi_device_bid(device),
- (u32) ec->common.gpe_bit);
-
- if (!first_ec)
- first_ec = device;
-
- end:
- if (result)
- kfree(ec);
-
- return result;
-}
-static int acpi_ec_intr_add(struct acpi_device *device)
-{
- int result = 0;
- acpi_status status = AE_OK;
- union acpi_ec *ec = NULL;
-
-
- if (!device)
- return -EINVAL;
-
- ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
- if (!ec)
- return -ENOMEM;
- memset(ec, 0, sizeof(union acpi_ec));
-
- ec->common.handle = device->handle;
- ec->common.uid = -1;
- atomic_set(&ec->intr.pending_gpe, 0);
- atomic_set(&ec->intr.leaving_burst, 1);
- init_MUTEX(&ec->intr.sem);
- init_waitqueue_head(&ec->intr.wait);
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
acpi_driver_data(device) = ec;
/* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
- &ec->common.global_lock);
+ acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
@@ -1081,7 +651,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler);
- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
&acpi_ec_gpe_handler);
kfree(ec_ecdt);
@@ -1089,11 +659,10 @@ static int acpi_ec_intr_add(struct acpi_device *device)
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
- status =
- acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
- &ec->common.gpe_bit);
+ status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Obtaining GPE bit assignment\n");
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Obtaining GPE bit assignment"));
result = -ENODEV;
goto end;
}
@@ -1102,9 +671,9 @@ static int acpi_ec_intr_add(struct acpi_device *device)
if (result)
goto end;
- printk(KERN_INFO PREFIX "%s [%s] (gpe %d) interrupt mode.\n",
- acpi_device_name(device), acpi_device_bid(device),
- (u32) ec->common.gpe_bit);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
+ acpi_device_name(device), acpi_device_bid(device),
+ (u32) ec->gpe));
if (!first_ec)
first_ec = device;
@@ -1118,8 +687,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
static int acpi_ec_remove(struct acpi_device *device, int type)
{
- union acpi_ec *ec = NULL;
-
+ struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
@@ -1136,8 +704,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
static acpi_status
acpi_ec_io_ports(struct acpi_resource *resource, void *context)
{
- union acpi_ec *ec = context;
- struct acpi_generic_address *addr;
+ struct acpi_ec *ec = (struct acpi_ec *)context;
if (resource->type != ACPI_RESOURCE_TYPE_IO) {
return AE_OK;
@@ -1148,27 +715,21 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context)
* the second address region returned is the status/command
* port.
*/
- if (ec->common.data_addr.register_bit_width == 0) {
- addr = &ec->common.data_addr;
- } else if (ec->common.command_addr.register_bit_width == 0) {
- addr = &ec->common.command_addr;
+ if (ec->data_addr == 0) {
+ ec->data_addr = resource->data.io.minimum;
+ } else if (ec->command_addr == 0) {
+ ec->command_addr = resource->data.io.minimum;
} else {
return AE_CTRL_TERMINATE;
}
- addr->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
- addr->register_bit_width = 8;
- addr->register_bit_offset = 0;
- addr->address = resource->data.io.minimum;
-
return AE_OK;
}
static int acpi_ec_start(struct acpi_device *device)
{
acpi_status status = AE_OK;
- union acpi_ec *ec = NULL;
-
+ struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
@@ -1181,40 +742,35 @@ static int acpi_ec_start(struct acpi_device *device)
/*
* Get I/O port addresses. Convert to GAS format.
*/
- status = acpi_walk_resources(ec->common.handle, METHOD_NAME__CRS,
+ status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
acpi_ec_io_ports, ec);
- if (ACPI_FAILURE(status)
- || ec->common.command_addr.register_bit_width == 0) {
- printk(KERN_ERR PREFIX "Error getting I/O port addresses\n");
+ if (ACPI_FAILURE(status) || ec->command_addr == 0) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Error getting I/O port addresses"));
return -ENODEV;
}
- ec->common.status_addr = ec->common.command_addr;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n",
- (u32) ec->common.gpe_bit,
- (u32) ec->common.command_addr.address,
- (u32) ec->common.data_addr.address));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
+ ec->gpe, ec->command_addr, ec->data_addr));
/*
* Install GPE handler
*/
- status = acpi_install_gpe_handler(NULL, ec->common.gpe_bit,
+ status = acpi_install_gpe_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status)) {
return -ENODEV;
}
- acpi_set_gpe_type(NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+ acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
- status = acpi_install_address_space_handler(ec->common.handle,
+ status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
&acpi_ec_space_setup, ec);
if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
- &acpi_ec_gpe_handler);
+ acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
return -ENODEV;
}
@@ -1224,23 +780,20 @@ static int acpi_ec_start(struct acpi_device *device)
static int acpi_ec_stop(struct acpi_device *device, int type)
{
acpi_status status = AE_OK;
- union acpi_ec *ec = NULL;
-
+ struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
- status = acpi_remove_address_space_handler(ec->common.handle,
+ status = acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler);
if (ACPI_FAILURE(status))
return -ENODEV;
- status =
- acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
- &acpi_ec_gpe_handler);
+ status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -1251,76 +804,29 @@ static acpi_status __init
acpi_fake_ecdt_callback(acpi_handle handle,
u32 Level, void *context, void **retval)
{
-
- if (acpi_ec_poll_mode)
- return acpi_fake_ecdt_poll_callback(handle,
- Level, context, retval);
- else
- return acpi_fake_ecdt_intr_callback(handle,
- Level, context, retval);
-}
-
-static acpi_status __init
-acpi_fake_ecdt_poll_callback(acpi_handle handle,
- u32 Level, void *context, void **retval)
-{
- acpi_status status;
-
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- acpi_ec_io_ports, ec_ecdt);
- if (ACPI_FAILURE(status))
- return status;
- ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
-
- ec_ecdt->common.uid = -1;
- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
-
- status =
- acpi_evaluate_integer(handle, "_GPE", NULL,
- &ec_ecdt->common.gpe_bit);
- if (ACPI_FAILURE(status))
- return status;
- init_MUTEX(&ec_ecdt->poll.sem);
- ec_ecdt->common.global_lock = TRUE;
- ec_ecdt->common.handle = handle;
-
- printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
- (u32) ec_ecdt->common.gpe_bit,
- (u32) ec_ecdt->common.command_addr.address,
- (u32) ec_ecdt->common.data_addr.address);
-
- return AE_CTRL_TERMINATE;
-}
-
-static acpi_status __init
-acpi_fake_ecdt_intr_callback(acpi_handle handle,
- u32 Level, void *context, void **retval)
-{
acpi_status status;
- init_MUTEX(&ec_ecdt->intr.sem);
- init_waitqueue_head(&ec_ecdt->intr.wait);
+ mutex_init(&ec_ecdt->lock);
+ if (acpi_ec_mode == EC_INTR) {
+ init_waitqueue_head(&ec_ecdt->wait);
+ }
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
acpi_ec_io_ports, ec_ecdt);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
- ec_ecdt->common.uid = -1;
- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
+ ec_ecdt->uid = -1;
+ acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
- status =
- acpi_evaluate_integer(handle, "_GPE", NULL,
- &ec_ecdt->common.gpe_bit);
+ status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->common.global_lock = TRUE;
- ec_ecdt->common.handle = handle;
+ ec_ecdt->global_lock = TRUE;
+ ec_ecdt->handle = handle;
- printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
- (u32) ec_ecdt->common.gpe_bit,
- (u32) ec_ecdt->common.command_addr.address,
- (u32) ec_ecdt->common.data_addr.address);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+ ec_ecdt->gpe, ec_ecdt->command_addr,
+ ec_ecdt->data_addr));
return AE_CTRL_TERMINATE;
}
@@ -1340,14 +846,14 @@ static int __init acpi_ec_fake_ecdt(void)
acpi_status status;
int ret = 0;
- printk(KERN_INFO PREFIX "Try to make an fake ECDT\n");
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+ ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec_ecdt) {
ret = -ENOMEM;
goto error;
}
- memset(ec_ecdt, 0, sizeof(union acpi_ec));
+ memset(ec_ecdt, 0, sizeof(struct acpi_ec));
status = acpi_get_devices(ACPI_EC_HID,
acpi_fake_ecdt_callback, NULL, NULL);
@@ -1355,24 +861,16 @@ static int __init acpi_ec_fake_ecdt(void)
kfree(ec_ecdt);
ec_ecdt = NULL;
ret = -ENODEV;
+ ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
goto error;
}
return 0;
error:
- printk(KERN_ERR PREFIX "Can't make an fake ECDT\n");
return ret;
}
static int __init acpi_ec_get_real_ecdt(void)
{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_get_real_ecdt();
- else
- return acpi_ec_intr_get_real_ecdt();
-}
-
-static int __init acpi_ec_poll_get_real_ecdt(void)
-{
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
@@ -1382,80 +880,35 @@ static int __init acpi_ec_poll_get_real_ecdt(void)
if (ACPI_FAILURE(status))
return -ENODEV;
- printk(KERN_INFO PREFIX "Found ECDT\n");
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
/*
* Generate a temporary ec context to use until the namespace is scanned
*/
- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+ ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec_ecdt)
return -ENOMEM;
- memset(ec_ecdt, 0, sizeof(union acpi_ec));
-
- ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
- ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
- ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
- ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
- init_MUTEX(&ec_ecdt->poll.sem);
- /* use the GL just to be safe */
- ec_ecdt->common.global_lock = TRUE;
- ec_ecdt->common.uid = ecdt_ptr->uid;
+ memset(ec_ecdt, 0, sizeof(struct acpi_ec));
- status =
- acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
- if (ACPI_FAILURE(status)) {
- goto error;
+ mutex_init(&ec_ecdt->lock);
+ if (acpi_ec_mode == EC_INTR) {
+ init_waitqueue_head(&ec_ecdt->wait);
}
-
- return 0;
- error:
- printk(KERN_ERR PREFIX "Could not use ECDT\n");
- kfree(ec_ecdt);
- ec_ecdt = NULL;
-
- return -ENODEV;
-}
-
-static int __init acpi_ec_intr_get_real_ecdt(void)
-{
- acpi_status status;
- struct acpi_table_ecdt *ecdt_ptr;
-
- status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &ecdt_ptr);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- printk(KERN_INFO PREFIX "Found ECDT\n");
-
- /*
- * Generate a temporary ec context to use until the namespace is scanned
- */
- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
- if (!ec_ecdt)
- return -ENOMEM;
- memset(ec_ecdt, 0, sizeof(union acpi_ec));
-
- init_MUTEX(&ec_ecdt->intr.sem);
- init_waitqueue_head(&ec_ecdt->intr.wait);
- ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
- ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
- ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
- ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
+ ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
+ ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
+ ec_ecdt->gpe = ecdt_ptr->gpe_bit;
/* use the GL just to be safe */
- ec_ecdt->common.global_lock = TRUE;
- ec_ecdt->common.uid = ecdt_ptr->uid;
+ ec_ecdt->global_lock = TRUE;
+ ec_ecdt->uid = ecdt_ptr->uid;
- status =
- acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
+ status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
if (ACPI_FAILURE(status)) {
goto error;
}
return 0;
error:
- printk(KERN_ERR PREFIX "Could not use ECDT\n");
+ ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
kfree(ec_ecdt);
ec_ecdt = NULL;
@@ -1480,14 +933,14 @@ int __init acpi_ec_ecdt_probe(void)
/*
* Install GPE handler
*/
- status = acpi_install_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+ status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec_ecdt);
if (ACPI_FAILURE(status)) {
goto error;
}
- acpi_set_gpe_type(NULL, ec_ecdt->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec_ecdt->common.gpe_bit, ACPI_NOT_ISR);
+ acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR);
status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC,
@@ -1495,7 +948,7 @@ int __init acpi_ec_ecdt_probe(void)
&acpi_ec_space_setup,
ec_ecdt);
if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
&acpi_ec_gpe_handler);
goto error;
}
@@ -1503,7 +956,7 @@ int __init acpi_ec_ecdt_probe(void)
return 0;
error:
- printk(KERN_ERR PREFIX "Could not use ECDT\n");
+ ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
kfree(ec_ecdt);
ec_ecdt = NULL;
@@ -1514,7 +967,6 @@ static int __init acpi_ec_init(void)
{
int result = 0;
-
if (acpi_disabled)
return 0;
@@ -1562,13 +1014,14 @@ static int __init acpi_ec_set_intr_mode(char *str)
return 0;
if (intr) {
- acpi_ec_poll_mode = EC_INTR;
- acpi_ec_driver.ops.add = acpi_ec_intr_add;
+ acpi_ec_mode = EC_INTR;
} else {
- acpi_ec_poll_mode = EC_POLL;
- acpi_ec_driver.ops.add = acpi_ec_poll_add;
+ acpi_ec_mode = EC_POLL;
}
- printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling");
+ acpi_ec_driver.ops.add = acpi_ec_add;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n",
+ intr ? "interrupt" : "polling"));
+
return 1;
}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index 6eef4efddcf..bf63edc6608 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -331,7 +331,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context)
static u32 acpi_ev_global_lock_handler(void *context)
{
u8 acquired = FALSE;
- acpi_status status;
/*
* Attempt to get the lock
@@ -342,20 +341,8 @@ static u32 acpi_ev_global_lock_handler(void *context)
if (acquired) {
/* Got the lock, now wake all threads waiting for it */
-
acpi_gbl_global_lock_acquired = TRUE;
-
- /* Run the Global Lock thread which will signal all waiting threads */
-
- status =
- acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER,
- acpi_ev_global_lock_thread, context);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not queue Global Lock thread"));
-
- return (ACPI_INTERRUPT_NOT_HANDLED);
- }
+ acpi_ev_global_lock_thread(context);
}
return (ACPI_INTERRUPT_HANDLED);
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 5b3c7a85eb9..203d1359190 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -225,13 +225,12 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
if (!
(ACPI_STRNCMP
(object_hID.value, PCI_ROOT_HID_STRING,
- sizeof(PCI_ROOT_HID_STRING))
- ||
- !(ACPI_STRNCMP
- (object_hID.value,
- PCI_EXPRESS_ROOT_HID_STRING,
- sizeof(PCI_EXPRESS_ROOT_HID_STRING)))))
- {
+ sizeof(PCI_ROOT_HID_STRING)))
+ ||
+ !(ACPI_STRNCMP
+ (object_hID.value,
+ PCI_EXPRESS_ROOT_HID_STRING,
+ sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
/* Install a handler for this PCI root bridge */
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 3a39c2e8e10..bf90f04f2c6 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -266,10 +266,10 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
walk_state->thread->thread_id)
&& (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
ACPI_ERROR((AE_INFO,
- "Thread %X cannot release Mutex [%4.4s] acquired by thread %X",
- (u32) walk_state->thread->thread_id,
+ "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
+ (unsigned long)walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node),
- (u32) obj_desc->mutex.owner_thread->thread_id));
+ (unsigned long)obj_desc->mutex.owner_thread->thread_id));
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index ba5686fa475..8a0324b43e5 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -189,8 +189,12 @@ find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv)
bus = tmp;
if (seg == find->seg && bus == find->bus)
+ {
find->handle = handle;
- status = AE_OK;
+ status = AE_CTRL_TERMINATE;
+ }
+ else
+ status = AE_OK;
exit:
kfree(buffer.pointer);
return status;
@@ -267,9 +271,9 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
{
acpi_status status;
- if (dev->firmware_data) {
+ if (dev->archdata.acpi_handle) {
printk(KERN_WARNING PREFIX
- "Drivers changed 'firmware_data' for %s\n", dev->bus_id);
+ "Drivers changed 'acpi_handle' for %s\n", dev->bus_id);
return -EINVAL;
}
get_device(dev);
@@ -278,25 +282,26 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
put_device(dev);
return -EINVAL;
}
- dev->firmware_data = handle;
+ dev->archdata.acpi_handle = handle;
return 0;
}
static int acpi_unbind_one(struct device *dev)
{
- if (!dev->firmware_data)
+ if (!dev->archdata.acpi_handle)
return 0;
- if (dev == acpi_get_physical_device(dev->firmware_data)) {
+ if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
/* acpi_get_physical_device increase refcnt by one */
put_device(dev);
- acpi_detach_data(dev->firmware_data, acpi_glue_data_handler);
- dev->firmware_data = NULL;
+ acpi_detach_data(dev->archdata.acpi_handle,
+ acpi_glue_data_handler);
+ dev->archdata.acpi_handle = NULL;
/* acpi_bind_one increase refcnt by one */
put_device(dev);
} else {
printk(KERN_ERR PREFIX
- "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id);
+ "Oops, 'acpi_handle' corrupt for %s\n", dev->bus_id);
}
return 0;
}
@@ -328,7 +333,8 @@ static int acpi_platform_notify(struct device *dev)
if (!ret) {
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer);
+ acpi_get_name(dev->archdata.acpi_handle,
+ ACPI_FULL_PATHNAME, &buffer);
DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer);
kfree(buffer.pointer);
} else
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 6fbb4204889..1e7abef404b 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -3,6 +3,7 @@
*
*
* Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ * Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,10 +20,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define IBM_VERSION "0.12a"
+#define IBM_VERSION "0.13"
/*
* Changelog:
+ *
+ * 2006-11-22 0.13 new maintainer
+ * changelog now lives in git commit history, and will
+ * not be updated further in-file.
*
* 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
* 2005-03-17 0.11 support for 600e, 770x
@@ -77,9 +82,16 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/string.h>
+
#include <linux/proc_fs.h>
+#include <linux/backlight.h>
#include <asm/uaccess.h>
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
#include <acpi/acpi_drivers.h>
#include <acpi/acnamesp.h>
@@ -88,7 +100,7 @@
#define IBM_FILE "ibm_acpi"
#define IBM_URL "http://ibm-acpi.sf.net/"
-MODULE_AUTHOR("Borislav Deianov");
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
MODULE_DESCRIPTION(IBM_DESC);
MODULE_VERSION(IBM_VERSION);
MODULE_LICENSE("GPL");
@@ -116,28 +128,6 @@ static acpi_handle root_handle = NULL;
static char *object##_path; \
static char *object##_paths[] = { paths }
-/*
- * The following models are supported to various degrees:
- *
- * 570, 600e, 600x, 770e, 770x
- * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p
- * G40, G41
- * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51
- * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43
- * X20, X21, X22, X23, X24, X30, X31, X40
- *
- * The following models have no supported features:
- *
- * 240, 240x, i1400
- *
- * Still missing DSDTs for the following models:
- *
- * A20p, A22e, A22m
- * R52
- * S31
- * T43p
- */
-
IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
"\\_SB.PCI.ISA.EC", /* 570 */
"\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
@@ -167,8 +157,10 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
"\\_SB.PCI.ISA.SLCE", /* 570 */
); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
#endif
+#ifdef CONFIG_ACPI_IBM_BAY
IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
"\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
+ "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
"\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
); /* A21e, R30, R31 */
@@ -183,6 +175,7 @@ IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
"_EJ0", /* 770x */
); /* all others */
+#endif
/* don't list other alternatives as we install a notify handler on the 570 */
IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
@@ -203,7 +196,7 @@ IBM_HANDLE(led, ec, "SLED", /* 570 */
IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
-IBM_HANDLE(fans, ec, "FANS"); /* X31, X40 */
+IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
"\\FSPD", /* 600e/x, 770e, 770x */
@@ -216,6 +209,152 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
#define IBM_HKEY_HID "IBM0068"
#define IBM_PCI_HID "PNP0A03"
+enum thermal_access_mode {
+ IBMACPI_THERMAL_NONE = 0, /* No thermal support */
+ IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
+ IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
+ IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
+ IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
+};
+
+#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+ s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
+};
+
+/*
+ * FAN ACCESS MODES
+ *
+ * IBMACPI_FAN_RD_ACPI_GFAN:
+ * ACPI GFAN method: returns fan level
+ *
+ * see IBMACPI_FAN_WR_ACPI_SFAN
+ * EC 0x2f not available if GFAN exists
+ *
+ * IBMACPI_FAN_WR_ACPI_SFAN:
+ * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
+ *
+ * EC 0x2f might be available *for reading*, but never for writing.
+ *
+ * IBMACPI_FAN_WR_TPEC:
+ * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
+ * on almost all ThinkPads
+ *
+ * Fan speed changes of any sort (including those caused by the
+ * disengaged mode) are usually done slowly by the firmware as the
+ * maximum ammount of fan duty cycle change per second seems to be
+ * limited.
+ *
+ * Reading is not available if GFAN exists.
+ * Writing is not available if SFAN exists.
+ *
+ * Bits
+ * 7 automatic mode engaged;
+ * (default operation mode of the ThinkPad)
+ * fan level is ignored in this mode.
+ * 6 disengage mode (takes precedence over bit 7);
+ * not available on all thinkpads. May disable
+ * the tachometer, and speeds up fan to 100% duty-cycle,
+ * which speeds it up far above the standard RPM
+ * levels. It is not impossible that it could cause
+ * hardware damage.
+ * 5-3 unused in some models. Extra bits for fan level
+ * in others, but still useless as all values above
+ * 7 map to the same speed as level 7 in these models.
+ * 2-0 fan level (0..7 usually)
+ * 0x00 = stop
+ * 0x07 = max (set when temperatures critical)
+ * Some ThinkPads may have other levels, see
+ * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
+ *
+ * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
+ * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
+ * does so, its initial value is meaningless (0x07).
+ *
+ * For firmware bugs, refer to:
+ * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * ----
+ *
+ * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
+ * Main fan tachometer reading (in RPM)
+ *
+ * This register is present on all ThinkPads with a new-style EC, and
+ * it is known not to be present on the A21m/e, and T22, as there is
+ * something else in offset 0x84 according to the ACPI DSDT. Other
+ * ThinkPads from this same time period (and earlier) probably lack the
+ * tachometer as well.
+ *
+ * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
+ * was never fixed by IBM to report the EC firmware version string
+ * probably support the tachometer (like the early X models), so
+ * detecting it is quite hard. We need more data to know for sure.
+ *
+ * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
+ * might result.
+ *
+ * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
+ * register is not invalidated in ThinkPads that disable tachometer
+ * readings. Thus, the tachometer readings go stale.
+ *
+ * For firmware bugs, refer to:
+ * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * IBMACPI_FAN_WR_ACPI_FANS:
+ * ThinkPad X31, X40, X41. Not available in the X60.
+ *
+ * FANS ACPI handle: takes three arguments: low speed, medium speed,
+ * high speed. ACPI DSDT seems to map these three speeds to levels
+ * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
+ * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
+ *
+ * The speeds are stored on handles
+ * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
+ *
+ * There are three default speed sets, acessible as handles:
+ * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
+ *
+ * ACPI DSDT switches which set is in use depending on various
+ * factors.
+ *
+ * IBMACPI_FAN_WR_TPEC is also available and should be used to
+ * command the fan. The X31/X40/X41 seems to have 8 fan levels,
+ * but the ACPI tables just mention level 7.
+ */
+
+enum fan_status_access_mode {
+ IBMACPI_FAN_NONE = 0, /* No fan status or control */
+ IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
+ IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+ IBMACPI_FAN_WR_NONE = 0, /* No fan control */
+ IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
+ IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
+ IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+ IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
+ IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
+ IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
+ * and also watchdog cmd */
+};
+
+enum { /* Fan control constants */
+ fan_status_offset = 0x2f, /* EC register 0x2f */
+ fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
+ * 0x84 must be read before 0x85 */
+
+ IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer
+ * disengaged */
+ IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan
+ * control */
+};
+
+static char *ibm_thinkpad_ec_found = NULL;
+
struct ibm_struct {
char *name;
char param[32];
@@ -243,6 +382,8 @@ struct ibm_struct {
static struct proc_dir_entry *proc_dir = NULL;
+static struct backlight_device *ibm_backlight_device = NULL;
+
#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -581,8 +722,7 @@ static int wan_status(void)
{
int status;
- if (!wan_supported ||
- !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+ if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
status = 0;
return status;
@@ -630,12 +770,15 @@ static int wan_write(char *buf)
return 0;
}
-static int video_supported;
-static int video_orig_autosw;
+enum video_access_mode {
+ IBMACPI_VIDEO_NONE = 0,
+ IBMACPI_VIDEO_570, /* 570 */
+ IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */
+ IBMACPI_VIDEO_NEW, /* all others */
+};
-#define VIDEO_570 1
-#define VIDEO_770 2
-#define VIDEO_NEW 3
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
static int video_init(void)
{
@@ -647,16 +790,16 @@ static int video_init(void)
if (!vid_handle)
/* video switching not supported on R30, R31 */
- video_supported = 0;
+ video_supported = IBMACPI_VIDEO_NONE;
else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
/* 570 */
- video_supported = VIDEO_570;
+ video_supported = IBMACPI_VIDEO_570;
else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
/* 600e/x, 770e, 770x */
- video_supported = VIDEO_770;
+ video_supported = IBMACPI_VIDEO_770;
else
/* all others */
- video_supported = VIDEO_NEW;
+ video_supported = IBMACPI_VIDEO_NEW;
return 0;
}
@@ -666,15 +809,15 @@ static int video_status(void)
int status = 0;
int i;
- if (video_supported == VIDEO_570) {
+ if (video_supported == IBMACPI_VIDEO_570) {
if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
status = i & 3;
- } else if (video_supported == VIDEO_770) {
+ } else if (video_supported == IBMACPI_VIDEO_770) {
if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
status |= 0x01 * i;
if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
status |= 0x02 * i;
- } else if (video_supported == VIDEO_NEW) {
+ } else if (video_supported == IBMACPI_VIDEO_NEW) {
acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
status |= 0x02 * i;
@@ -693,9 +836,10 @@ static int video_autosw(void)
{
int autosw = 0;
- if (video_supported == VIDEO_570)
+ if (video_supported == IBMACPI_VIDEO_570)
acpi_evalf(vid_handle, &autosw, "SWIT", "d");
- else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW)
+ else if (video_supported == IBMACPI_VIDEO_770 ||
+ video_supported == IBMACPI_VIDEO_NEW)
acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
return autosw & 1;
@@ -715,12 +859,12 @@ static int video_read(char *p)
len += sprintf(p + len, "status:\t\tsupported\n");
len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
- if (video_supported == VIDEO_NEW)
+ if (video_supported == IBMACPI_VIDEO_NEW)
len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
- if (video_supported == VIDEO_NEW)
+ if (video_supported == IBMACPI_VIDEO_NEW)
len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
@@ -735,7 +879,7 @@ static int video_switch(void)
if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
return -EIO;
- ret = video_supported == VIDEO_570 ?
+ ret = video_supported == IBMACPI_VIDEO_570 ?
acpi_evalf(ec_handle, NULL, "_Q16", "v") :
acpi_evalf(vid_handle, NULL, "VSWT", "v");
acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
@@ -745,9 +889,9 @@ static int video_switch(void)
static int video_expand(void)
{
- if (video_supported == VIDEO_570)
+ if (video_supported == IBMACPI_VIDEO_570)
return acpi_evalf(ec_handle, NULL, "_Q17", "v");
- else if (video_supported == VIDEO_770)
+ else if (video_supported == IBMACPI_VIDEO_770)
return acpi_evalf(vid_handle, NULL, "VEXP", "v");
else
return acpi_evalf(NULL, NULL, "\\VEXP", "v");
@@ -757,10 +901,10 @@ static int video_switch2(int status)
{
int ret;
- if (video_supported == VIDEO_570) {
+ if (video_supported == IBMACPI_VIDEO_570) {
ret = acpi_evalf(NULL, NULL,
"\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
- } else if (video_supported == VIDEO_770) {
+ } else if (video_supported == IBMACPI_VIDEO_770) {
int autosw = video_autosw();
if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
return -EIO;
@@ -796,10 +940,10 @@ static int video_write(char *buf)
enable |= 0x02;
} else if (strlencmp(cmd, "crt_disable") == 0) {
disable |= 0x02;
- } else if (video_supported == VIDEO_NEW &&
+ } else if (video_supported == IBMACPI_VIDEO_NEW &&
strlencmp(cmd, "dvi_enable") == 0) {
enable |= 0x08;
- } else if (video_supported == VIDEO_NEW &&
+ } else if (video_supported == IBMACPI_VIDEO_NEW &&
strlencmp(cmd, "dvi_disable") == 0) {
disable |= 0x08;
} else if (strlencmp(cmd, "auto_enable") == 0) {
@@ -898,6 +1042,7 @@ static int light_write(char *buf)
return 0;
}
+#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
static int _sta(acpi_handle handle)
{
int status;
@@ -907,6 +1052,7 @@ static int _sta(acpi_handle handle)
return status;
}
+#endif
#ifdef CONFIG_ACPI_IBM_DOCK
#define dock_docked() (_sta(dock_handle) & 1)
@@ -972,6 +1118,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event)
}
#endif
+#ifdef CONFIG_ACPI_IBM_BAY
static int bay_status_supported;
static int bay_status2_supported;
static int bay_eject_supported;
@@ -1047,6 +1194,7 @@ static void bay_notify(struct ibm_struct *ibm, u32 event)
{
acpi_bus_generate_event(ibm->device, event, 0);
}
+#endif
static int cmos_read(char *p)
{
@@ -1094,26 +1242,28 @@ static int cmos_write(char *buf)
return 0;
}
-static int led_supported;
-
-#define LED_570 1
-#define LED_OLD 2
-#define LED_NEW 3
+enum led_access_mode {
+ IBMACPI_LED_NONE = 0,
+ IBMACPI_LED_570, /* 570 */
+ IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ IBMACPI_LED_NEW, /* all others */
+};
+static enum led_access_mode led_supported;
static int led_init(void)
{
if (!led_handle)
/* led not supported on R30, R31 */
- led_supported = 0;
+ led_supported = IBMACPI_LED_NONE;
else if (strlencmp(led_path, "SLED") == 0)
/* 570 */
- led_supported = LED_570;
+ led_supported = IBMACPI_LED_570;
else if (strlencmp(led_path, "SYSL") == 0)
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- led_supported = LED_OLD;
+ led_supported = IBMACPI_LED_OLD;
else
/* all others */
- led_supported = LED_NEW;
+ led_supported = IBMACPI_LED_NEW;
return 0;
}
@@ -1130,7 +1280,7 @@ static int led_read(char *p)
}
len += sprintf(p + len, "status:\t\tsupported\n");
- if (led_supported == LED_570) {
+ if (led_supported == IBMACPI_LED_570) {
/* 570 */
int i, status;
for (i = 0; i < 8; i++) {
@@ -1179,13 +1329,13 @@ static int led_write(char *buf)
} else
return -EINVAL;
- if (led_supported == LED_570) {
+ if (led_supported == IBMACPI_LED_570) {
/* 570 */
led = 1 << led;
if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
led, led_sled_arg1[ind]))
return -EIO;
- } else if (led_supported == LED_OLD) {
+ } else if (led_supported == IBMACPI_LED_OLD) {
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
led = 1 << led;
ret = ec_write(EC_HLMS, led);
@@ -1272,50 +1422,142 @@ static int acpi_ec_write(int i, u8 v)
return 1;
}
-static int thermal_tmp_supported;
-static int thermal_updt_supported;
+static enum thermal_access_mode thermal_read_mode;
static int thermal_init(void)
{
- /* temperatures not supported on 570, G4x, R30, R31, R32 */
- thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
+ u8 t, ta1, ta2;
+ int i;
+ int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
- /* 600e/x, 770e, 770x */
- thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv");
+ if (ibm_thinkpad_ec_found && experimental) {
+ /*
+ * Direct EC access mode: sensors at registers
+ * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
+ * non-implemented, thermal sensors return 0x80 when
+ * not available
+ */
+
+ ta1 = ta2 = 0;
+ for (i = 0; i < 8; i++) {
+ if (likely(acpi_ec_read(0x78 + i, &t))) {
+ ta1 |= t;
+ } else {
+ ta1 = 0;
+ break;
+ }
+ if (likely(acpi_ec_read(0xC0 + i, &t))) {
+ ta2 |= t;
+ } else {
+ ta1 = 0;
+ break;
+ }
+ }
+ if (ta1 == 0) {
+ /* This is sheer paranoia, but we handle it anyway */
+ if (acpi_tmp7) {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "falling back to ACPI TMPx access mode\n");
+ thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
+ } else {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "disabling thermal sensors access\n");
+ thermal_read_mode = IBMACPI_THERMAL_NONE;
+ }
+ } else {
+ thermal_read_mode =
+ (ta2 != 0) ?
+ IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
+ }
+ } else if (acpi_tmp7) {
+ if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
+ /* 600e/x, 770e, 770x */
+ thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
+ } else {
+ /* Standard ACPI TMPx access, max 8 sensors */
+ thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
+ }
+ } else {
+ /* temperatures not supported on 570, G4x, R30, R31, R32 */
+ thermal_read_mode = IBMACPI_THERMAL_NONE;
+ }
return 0;
}
-static int thermal_read(char *p)
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
{
- int len = 0;
+ int i, t;
+ s8 tmp;
+ char tmpi[] = "TMPi";
- if (!thermal_tmp_supported)
- len += sprintf(p + len, "temperatures:\tnot supported\n");
- else {
- int i, t;
- char tmpi[] = "TMPi";
- s8 tmp[8];
+ if (!s)
+ return -EINVAL;
- if (thermal_updt_supported)
- if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+ switch (thermal_read_mode) {
+#if IBMACPI_MAX_THERMAL_SENSORS >= 16
+ case IBMACPI_THERMAL_TPEC_16:
+ for (i = 0; i < 8; i++) {
+ if (!acpi_ec_read(0xC0 + i, &tmp))
+ return -EIO;
+ s->temp[i + 8] = tmp * 1000;
+ }
+ /* fallthrough */
+#endif
+ case IBMACPI_THERMAL_TPEC_8:
+ for (i = 0; i < 8; i++) {
+ if (!acpi_ec_read(0x78 + i, &tmp))
return -EIO;
+ s->temp[i] = tmp * 1000;
+ }
+ return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
+ case IBMACPI_THERMAL_ACPI_UPDT:
+ if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+ return -EIO;
for (i = 0; i < 8; i++) {
tmpi[3] = '0' + i;
if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
return -EIO;
- if (thermal_updt_supported)
- tmp[i] = (t - 2732 + 5) / 10;
- else
- tmp[i] = t;
+ s->temp[i] = (t - 2732) * 100;
}
+ return 8;
- len += sprintf(p + len,
- "temperatures:\t%d %d %d %d %d %d %d %d\n",
- tmp[0], tmp[1], tmp[2], tmp[3],
- tmp[4], tmp[5], tmp[6], tmp[7]);
+ case IBMACPI_THERMAL_ACPI_TMP07:
+ for (i = 0; i < 8; i++) {
+ tmpi[3] = '0' + i;
+ if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+ return -EIO;
+ s->temp[i] = t * 1000;
+ }
+ return 8;
+
+ case IBMACPI_THERMAL_NONE:
+ default:
+ return 0;
}
+}
+
+static int thermal_read(char *p)
+{
+ int len = 0;
+ int n, i;
+ struct ibm_thermal_sensors_struct t;
+
+ n = thermal_get_sensors(&t);
+ if (unlikely(n < 0))
+ return n;
+
+ len += sprintf(p + len, "temperatures:\t");
+
+ if (n > 0) {
+ for (i = 0; i < (n - 1); i++)
+ len += sprintf(p + len, "%d ", t.temp[i] / 1000);
+ len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
+ } else
+ len += sprintf(p + len, "not supported\n");
return len;
}
@@ -1381,12 +1623,23 @@ static int ecdump_write(char *buf)
static int brightness_offset = 0x31;
+static int brightness_get(struct backlight_device *bd)
+{
+ u8 level;
+ if (!acpi_ec_read(brightness_offset, &level))
+ return -EIO;
+
+ level &= 0x7;
+
+ return level;
+}
+
static int brightness_read(char *p)
{
int len = 0;
- u8 level;
+ int level;
- if (!acpi_ec_read(brightness_offset, &level)) {
+ if ((level = brightness_get(NULL)) < 0) {
len += sprintf(p + len, "level:\t\tunreadable\n");
} else {
len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
@@ -1401,16 +1654,34 @@ static int brightness_read(char *p)
#define BRIGHTNESS_UP 4
#define BRIGHTNESS_DOWN 5
-static int brightness_write(char *buf)
+static int brightness_set(int value)
{
int cmos_cmd, inc, i;
- u8 level;
+ int current_value = brightness_get(NULL);
+
+ value &= 7;
+
+ cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
+ inc = value > current_value ? 1 : -1;
+ for (i = current_value; i != value; i += inc) {
+ if (!cmos_eval(cmos_cmd))
+ return -EIO;
+ if (!acpi_ec_write(brightness_offset, i + inc))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int brightness_write(char *buf)
+{
+ int level;
int new_level;
char *cmd;
while ((cmd = next_cmd(&buf))) {
- if (!acpi_ec_read(brightness_offset, &level))
- return -EIO;
+ if ((level = brightness_get(NULL)) < 0)
+ return level;
level &= 7;
if (strlencmp(cmd, "up") == 0) {
@@ -1423,19 +1694,44 @@ static int brightness_write(char *buf)
} else
return -EINVAL;
- cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
- inc = new_level > level ? 1 : -1;
- for (i = level; i != new_level; i += inc) {
- if (!cmos_eval(cmos_cmd))
- return -EIO;
- if (!acpi_ec_write(brightness_offset, i + inc))
- return -EIO;
- }
+ brightness_set(new_level);
}
return 0;
}
+static int brightness_update_status(struct backlight_device *bd)
+{
+ return brightness_set(bd->props->brightness);
+}
+
+static struct backlight_properties ibm_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = brightness_get,
+ .update_status = brightness_update_status,
+ .max_brightness = 7,
+};
+
+static int brightness_init(void)
+{
+ ibm_backlight_device = backlight_device_register("ibm", NULL,
+ &ibm_backlight_data);
+ if (IS_ERR(ibm_backlight_device)) {
+ printk(IBM_ERR "Could not register backlight device\n");
+ return PTR_ERR(ibm_backlight_device);
+ }
+
+ return 0;
+}
+
+static void brightness_exit(void)
+{
+ if (ibm_backlight_device) {
+ backlight_device_unregister(ibm_backlight_device);
+ ibm_backlight_device = NULL;
+ }
+}
+
static int volume_offset = 0x30;
static int volume_read(char *p)
@@ -1522,86 +1818,482 @@ static int volume_write(char *buf)
return 0;
}
-static int fan_status_offset = 0x2f;
-static int fan_rpm_offset = 0x84;
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
-static int fan_read(char *p)
+static int fan_control_status_known;
+static u8 fan_control_initial_status;
+
+static void fan_watchdog_fire(struct work_struct *ignored);
+static int fan_watchdog_maxinterval;
+static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
+
+static int fan_init(void)
{
- int len = 0;
- int s;
- u8 lo, hi, status;
+ fan_status_access_mode = IBMACPI_FAN_NONE;
+ fan_control_access_mode = IBMACPI_FAN_WR_NONE;
+ fan_control_commands = 0;
+ fan_control_status_known = 1;
+ fan_watchdog_maxinterval = 0;
if (gfan_handle) {
/* 570, 600e/x, 770e, 770x */
- if (!acpi_evalf(gfan_handle, &s, NULL, "d"))
- return -EIO;
+ fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
+ } else {
+ /* all other ThinkPads: note that even old-style
+ * ThinkPad ECs supports the fan control register */
+ if (likely(acpi_ec_read(fan_status_offset,
+ &fan_control_initial_status))) {
+ fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
+
+ /* In some ThinkPads, neither the EC nor the ACPI
+ * DSDT initialize the fan status, and it ends up
+ * being set to 0x07 when it *could* be either
+ * 0x07 or 0x80.
+ *
+ * Enable for TP-1Y (T43), TP-78 (R51e),
+ * TP-76 (R52), TP-70 (T43, R52), which are known
+ * to be buggy. */
+ if (fan_control_initial_status == 0x07 &&
+ ibm_thinkpad_ec_found &&
+ ((ibm_thinkpad_ec_found[0] == '1' &&
+ ibm_thinkpad_ec_found[1] == 'Y') ||
+ (ibm_thinkpad_ec_found[0] == '7' &&
+ (ibm_thinkpad_ec_found[1] == '6' ||
+ ibm_thinkpad_ec_found[1] == '8' ||
+ ibm_thinkpad_ec_found[1] == '0'))
+ )) {
+ printk(IBM_NOTICE
+ "fan_init: initial fan status is "
+ "unknown, assuming it is in auto "
+ "mode\n");
+ fan_control_status_known = 0;
+ }
+ } else {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "fan status and control unavailable\n");
+ return 0;
+ }
+ }
- len += sprintf(p + len, "level:\t\t%d\n", s);
+ if (sfan_handle) {
+ /* 570, 770x-JL */
+ fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
+ fan_control_commands |=
+ IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
} else {
+ if (!gfan_handle) {
+ /* gfan without sfan means no fan control */
+ /* all other models implement TP EC 0x2f control */
+
+ if (fans_handle) {
+ /* X31, X40, X41 */
+ fan_control_access_mode =
+ IBMACPI_FAN_WR_ACPI_FANS;
+ fan_control_commands |=
+ IBMACPI_FAN_CMD_SPEED |
+ IBMACPI_FAN_CMD_LEVEL |
+ IBMACPI_FAN_CMD_ENABLE;
+ } else {
+ fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
+ fan_control_commands |=
+ IBMACPI_FAN_CMD_LEVEL |
+ IBMACPI_FAN_CMD_ENABLE;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int fan_get_status(u8 *status)
+{
+ u8 s;
+
+ /* TODO:
+ * Add IBMACPI_FAN_RD_ACPI_FANS ? */
+
+ switch (fan_status_access_mode) {
+ case IBMACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+
+ if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+ return -EIO;
+
+ if (likely(status))
+ *status = s & 0x07;
+
+ break;
+
+ case IBMACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */
- if (!acpi_ec_read(fan_status_offset, &status))
- len += sprintf(p + len, "status:\t\tunreadable\n");
- else
- len += sprintf(p + len, "status:\t\t%s\n",
- enabled(status, 7));
+ if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+ return -EIO;
- if (!acpi_ec_read(fan_rpm_offset, &lo) ||
- !acpi_ec_read(fan_rpm_offset + 1, &hi))
- len += sprintf(p + len, "speed:\t\tunreadable\n");
- else
- len += sprintf(p + len, "speed:\t\t%d\n",
- (hi << 8) + lo);
+ if (likely(status))
+ *status = s;
+
+ break;
+
+ default:
+ return -ENXIO;
}
- if (sfan_handle)
- /* 570, 770x-JL */
- len += sprintf(p + len, "commands:\tlevel <level>"
- " (<level> is 0-7)\n");
- if (!gfan_handle)
+ return 0;
+}
+
+static int fan_get_speed(unsigned int *speed)
+{
+ u8 hi, lo;
+
+ switch (fan_status_access_mode) {
+ case IBMACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */
- len += sprintf(p + len, "commands:\tenable, disable\n");
- if (fans_handle)
- /* X31, X40 */
+ if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+ !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+ return -EIO;
+
+ if (likely(speed))
+ *speed = (hi << 8) | lo;
+
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void fan_exit(void)
+{
+ cancel_delayed_work(&fan_watchdog_task);
+ flush_scheduled_work();
+}
+
+static void fan_watchdog_reset(void)
+{
+ static int fan_watchdog_active = 0;
+
+ if (fan_watchdog_active)
+ cancel_delayed_work(&fan_watchdog_task);
+
+ if (fan_watchdog_maxinterval > 0) {
+ fan_watchdog_active = 1;
+ if (!schedule_delayed_work(&fan_watchdog_task,
+ msecs_to_jiffies(fan_watchdog_maxinterval
+ * 1000))) {
+ printk(IBM_ERR "failed to schedule the fan watchdog, "
+ "watchdog will not trigger\n");
+ }
+ } else
+ fan_watchdog_active = 0;
+}
+
+static int fan_read(char *p)
+{
+ int len = 0;
+ int rc;
+ u8 status;
+ unsigned int speed = 0;
+
+ switch (fan_status_access_mode) {
+ case IBMACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+ if ((rc = fan_get_status(&status)) < 0)
+ return rc;
+
+ len += sprintf(p + len, "status:\t\t%s\n"
+ "level:\t\t%d\n",
+ (status != 0) ? "enabled" : "disabled", status);
+ break;
+
+ case IBMACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if ((rc = fan_get_status(&status)) < 0)
+ return rc;
+
+ if (unlikely(!fan_control_status_known)) {
+ if (status != fan_control_initial_status)
+ fan_control_status_known = 1;
+ else
+ /* Return most likely status. In fact, it
+ * might be the only possible status */
+ status = IBMACPI_FAN_EC_AUTO;
+ }
+
+ len += sprintf(p + len, "status:\t\t%s\n",
+ (status != 0) ? "enabled" : "disabled");
+
+ /* No ThinkPad boots on disengaged mode, we can safely
+ * assume the tachometer is online if fan control status
+ * was unknown */
+ if ((rc = fan_get_speed(&speed)) < 0)
+ return rc;
+
+ len += sprintf(p + len, "speed:\t\t%d\n", speed);
+
+ if (status & IBMACPI_FAN_EC_DISENGAGED)
+ /* Disengaged mode takes precedence */
+ len += sprintf(p + len, "level:\t\tdisengaged\n");
+ else if (status & IBMACPI_FAN_EC_AUTO)
+ len += sprintf(p + len, "level:\t\tauto\n");
+ else
+ len += sprintf(p + len, "level:\t\t%d\n", status);
+ break;
+
+ case IBMACPI_FAN_NONE:
+ default:
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ }
+
+ if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
+ len += sprintf(p + len, "commands:\tlevel <level>");
+
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_SFAN:
+ len += sprintf(p + len, " (<level> is 0-7)\n");
+ break;
+
+ default:
+ len += sprintf(p + len, " (<level> is 0-7, "
+ "auto, disengaged)\n");
+ break;
+ }
+ }
+
+ if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
+ len += sprintf(p + len, "commands:\tenable, disable\n"
+ "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
+ "1-120 (seconds))\n");
+
+ if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
len += sprintf(p + len, "commands:\tspeed <speed>"
" (<speed> is 0-65535)\n");
return len;
}
-static int fan_write(char *buf)
+static int fan_set_level(int level)
{
- char *cmd;
- int level, speed;
-
- while ((cmd = next_cmd(&buf))) {
- if (sfan_handle &&
- sscanf(cmd, "level %d", &level) == 1 &&
- level >= 0 && level <= 7) {
- /* 570, 770x-JL */
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_SFAN:
+ if (level >= 0 && level <= 7) {
if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
return -EIO;
- } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) {
- /* all except 570, 600e/x, 770e, 770x */
- if (!acpi_ec_write(fan_status_offset, 0x80))
- return -EIO;
- } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) {
- /* all except 570, 600e/x, 770e, 770x */
- if (!acpi_ec_write(fan_status_offset, 0x00))
- return -EIO;
- } else if (fans_handle &&
- sscanf(cmd, "speed %d", &speed) == 1 &&
- speed >= 0 && speed <= 65535) {
- /* X31, X40 */
+ } else
+ return -EINVAL;
+ break;
+
+ case IBMACPI_FAN_WR_ACPI_FANS:
+ case IBMACPI_FAN_WR_TPEC:
+ if ((level != IBMACPI_FAN_EC_AUTO) &&
+ (level != IBMACPI_FAN_EC_DISENGAGED) &&
+ ((level < 0) || (level > 7)))
+ return -EINVAL;
+
+ if (!acpi_ec_write(fan_status_offset, level))
+ return -EIO;
+ else
+ fan_control_status_known = 1;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_enable(void)
+{
+ u8 s;
+ int rc;
+
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_FANS:
+ case IBMACPI_FAN_WR_TPEC:
+ if ((rc = fan_get_status(&s)) < 0)
+ return rc;
+
+ /* Don't go out of emergency fan mode */
+ if (s != 7)
+ s = IBMACPI_FAN_EC_AUTO;
+
+ if (!acpi_ec_write(fan_status_offset, s))
+ return -EIO;
+ else
+ fan_control_status_known = 1;
+ break;
+
+ case IBMACPI_FAN_WR_ACPI_SFAN:
+ if ((rc = fan_get_status(&s)) < 0)
+ return rc;
+
+ s &= 0x07;
+
+ /* Set fan to at least level 4 */
+ if (s < 4)
+ s = 4;
+
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+ return -EIO;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_disable(void)
+{
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_FANS:
+ case IBMACPI_FAN_WR_TPEC:
+ if (!acpi_ec_write(fan_status_offset, 0x00))
+ return -EIO;
+ else
+ fan_control_status_known = 1;
+ break;
+
+ case IBMACPI_FAN_WR_ACPI_SFAN:
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+ return -EIO;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_speed(int speed)
+{
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_FANS:
+ if (speed >= 0 && speed <= 65535) {
if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
speed, speed, speed))
return -EIO;
} else
return -EINVAL;
- }
+ break;
+ default:
+ return -ENXIO;
+ }
return 0;
}
+static int fan_write_cmd_level(const char *cmd, int *rc)
+{
+ int level;
+
+ if (strlencmp(cmd, "level auto") == 0)
+ level = IBMACPI_FAN_EC_AUTO;
+ else if (strlencmp(cmd, "level disengaged") == 0)
+ level = IBMACPI_FAN_EC_DISENGAGED;
+ else if (sscanf(cmd, "level %d", &level) != 1)
+ return 0;
+
+ if ((*rc = fan_set_level(level)) == -ENXIO)
+ printk(IBM_ERR "level command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_enable(const char *cmd, int *rc)
+{
+ if (strlencmp(cmd, "enable") != 0)
+ return 0;
+
+ if ((*rc = fan_set_enable()) == -ENXIO)
+ printk(IBM_ERR "enable command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_disable(const char *cmd, int *rc)
+{
+ if (strlencmp(cmd, "disable") != 0)
+ return 0;
+
+ if ((*rc = fan_set_disable()) == -ENXIO)
+ printk(IBM_ERR "disable command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_speed(const char *cmd, int *rc)
+{
+ int speed;
+
+ /* TODO:
+ * Support speed <low> <medium> <high> ? */
+
+ if (sscanf(cmd, "speed %d", &speed) != 1)
+ return 0;
+
+ if ((*rc = fan_set_speed(speed)) == -ENXIO)
+ printk(IBM_ERR "speed command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_watchdog(const char *cmd, int *rc)
+{
+ int interval;
+
+ if (sscanf(cmd, "watchdog %d", &interval) != 1)
+ return 0;
+
+ if (interval < 0 || interval > 120)
+ *rc = -EINVAL;
+ else
+ fan_watchdog_maxinterval = interval;
+
+ return 1;
+}
+
+static int fan_write(char *buf)
+{
+ char *cmd;
+ int rc = 0;
+
+ while (!rc && (cmd = next_cmd(&buf))) {
+ if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
+ fan_write_cmd_level(cmd, &rc)) &&
+ !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
+ (fan_write_cmd_enable(cmd, &rc) ||
+ fan_write_cmd_disable(cmd, &rc) ||
+ fan_write_cmd_watchdog(cmd, &rc))) &&
+ !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
+ fan_write_cmd_speed(cmd, &rc))
+ )
+ rc = -EINVAL;
+ else if (!rc)
+ fan_watchdog_reset();
+ }
+
+ return rc;
+}
+
+static void fan_watchdog_fire(struct work_struct *ignored)
+{
+ printk(IBM_NOTICE "fan watchdog: enabling fan\n");
+ if (fan_set_enable()) {
+ printk(IBM_ERR "fan watchdog: error while enabling fan\n");
+ /* reschedule for later */
+ fan_watchdog_reset();
+ }
+}
+
static struct ibm_struct ibms[] = {
{
.name = "driver",
@@ -1662,6 +2354,7 @@ static struct ibm_struct ibms[] = {
.type = ACPI_SYSTEM_NOTIFY,
},
#endif
+#ifdef CONFIG_ACPI_IBM_BAY
{
.name = "bay",
.init = bay_init,
@@ -1671,6 +2364,7 @@ static struct ibm_struct ibms[] = {
.handle = &bay_handle,
.type = ACPI_SYSTEM_NOTIFY,
},
+#endif
{
.name = "cmos",
.read = cmos_read,
@@ -1702,18 +2396,20 @@ static struct ibm_struct ibms[] = {
.name = "brightness",
.read = brightness_read,
.write = brightness_write,
- .experimental = 1,
+ .init = brightness_init,
+ .exit = brightness_exit,
},
{
.name = "volume",
.read = volume_read,
.write = volume_write,
- .experimental = 1,
},
{
.name = "fan",
.read = fan_read,
.write = fan_write,
+ .init = fan_init,
+ .exit = fan_exit,
.experimental = 1,
},
};
@@ -1827,7 +2523,7 @@ static int __init register_driver(struct ibm_struct *ibm)
}
memset(ibm->driver, 0, sizeof(struct acpi_driver));
- sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name);
+ sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
ibm->driver->ids = ibm->hid;
ibm->driver->ops.add = &ibm_device_add;
@@ -1956,7 +2652,9 @@ IBM_PARAM(light);
#ifdef CONFIG_ACPI_IBM_DOCK
IBM_PARAM(dock);
#endif
+#ifdef CONFIG_ACPI_IBM_BAY
IBM_PARAM(bay);
+#endif
IBM_PARAM(cmos);
IBM_PARAM(led);
IBM_PARAM(beep);
@@ -1973,6 +2671,33 @@ static void acpi_ibm_exit(void)
ibm_exit(&ibms[i]);
remove_proc_entry(IBM_DIR, acpi_root_dir);
+
+ if (ibm_thinkpad_ec_found)
+ kfree(ibm_thinkpad_ec_found);
+}
+
+static char* __init check_dmi_for_ec(void)
+{
+ struct dmi_device *dev = NULL;
+ char ec_fw_string[18];
+
+ /*
+ * ThinkPad T23 or newer, A31 or newer, R50e or newer,
+ * X32 or newer, all Z series; Some models must have an
+ * up-to-date BIOS or they will not be detected.
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ */
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+ if (sscanf(dev->name,
+ "IBM ThinkPad Embedded Controller -[%17c",
+ ec_fw_string) == 1) {
+ ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
+ ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+ return kstrdup(ec_fw_string, GFP_KERNEL);
+ }
+ }
+ return NULL;
}
static int __init acpi_ibm_init(void)
@@ -1994,6 +2719,12 @@ static int __init acpi_ibm_init(void)
return -ENODEV;
}
+ /* Models with newer firmware report the EC in DMI */
+ ibm_thinkpad_ec_found = check_dmi_for_ec();
+ if (ibm_thinkpad_ec_found)
+ printk(IBM_INFO "ThinkPad EC firmware %s\n",
+ ibm_thinkpad_ec_found);
+
/* these handles are not required */
IBM_HANDLE_INIT(vid);
IBM_HANDLE_INIT(vid2);
@@ -2006,12 +2737,14 @@ static int __init acpi_ibm_init(void)
IBM_HANDLE_INIT(dock);
#endif
IBM_HANDLE_INIT(pci);
+#ifdef CONFIG_ACPI_IBM_BAY
IBM_HANDLE_INIT(bay);
if (bay_handle)
IBM_HANDLE_INIT(bay_ej);
IBM_HANDLE_INIT(bay2);
if (bay2_handle)
IBM_HANDLE_INIT(bay2_ej);
+#endif
IBM_HANDLE_INIT(beep);
IBM_HANDLE_INIT(ecrd);
IBM_HANDLE_INIT(ecwr);
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
index ec6b7f9ede3..2e17ec75af0 100644
--- a/drivers/acpi/motherboard.c
+++ b/drivers/acpi/motherboard.c
@@ -48,6 +48,12 @@ ACPI_MODULE_NAME("acpi_motherboard")
* the io ports if they really know they can use it, while
* still preventing hotplug PCI devices from using it.
*/
+
+/*
+ * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01
+ * and PNP0C02, redundant with acpi_reserve_io_ranges().
+ * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP.
+ */
static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
{
struct resource *requested_res = NULL;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2ed2d701f6e..b7ca020a056 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -50,6 +50,7 @@ ACPI_MODULE_NAME("osl")
struct acpi_os_dpc {
acpi_osd_exec_callback function;
void *context;
+ struct work_struct work;
};
#ifdef CONFIG_ACPI_CUSTOM_DSDT
@@ -564,12 +565,10 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
}
-static void acpi_os_execute_deferred(void *context)
+static void acpi_os_execute_deferred(struct work_struct *work)
{
- struct acpi_os_dpc *dpc = NULL;
+ struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
-
- dpc = context;
if (!dpc) {
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
return;
@@ -602,7 +601,6 @@ acpi_status acpi_os_execute(acpi_execute_type type,
{
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
- struct work_struct *task;
ACPI_FUNCTION_TRACE("os_queue_for_execution");
@@ -615,28 +613,22 @@ acpi_status acpi_os_execute(acpi_execute_type type,
/*
* Allocate/initialize DPC structure. Note that this memory will be
- * freed by the callee. The kernel handles the tq_struct list in a
+ * freed by the callee. The kernel handles the work_struct list in a
* way that allows us to also free its memory inside the callee.
* Because we may want to schedule several tasks with different
* parameters we can't use the approach some kernel code uses of
- * having a static tq_struct.
- * We can save time and code by allocating the DPC and tq_structs
- * from the same memory.
+ * having a static work_struct.
*/
- dpc =
- kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
- GFP_ATOMIC);
+ dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
if (!dpc)
return_ACPI_STATUS(AE_NO_MEMORY);
dpc->function = function;
dpc->context = context;
- task = (void *)(dpc + 1);
- INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
-
- if (!queue_work(kacpid_wq, task)) {
+ INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+ if (!queue_work(kacpid_wq, &dpc->work)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Call to queue_work() failed.\n"));
kfree(dpc);
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 6718198bfae..812d733fe81 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -307,7 +307,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
if (!link || !irq)
return -EINVAL;
- resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC);
+ resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
if (!resource)
return -ENOMEM;
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index e9dab54bd54..23a8a929557 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -216,10 +216,8 @@ static int acpi_power_off_device(acpi_handle handle)
{
int result = 0;
acpi_status status = AE_OK;
- struct acpi_device *device = NULL;
struct acpi_power_resource *resource = NULL;
-
result = acpi_power_get_context(handle, &resource);
if (result)
return result;
@@ -230,13 +228,13 @@ static int acpi_power_off_device(acpi_handle handle)
if (resource->references) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Resource [%s] is still in use, dereferencing\n",
- device->pnp.bus_id));
+ resource->device->pnp.bus_id));
return 0;
}
if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
- device->pnp.bus_id));
+ resource->device->pnp.bus_id));
return 0;
}
@@ -251,8 +249,7 @@ static int acpi_power_off_device(acpi_handle handle)
return -ENOEXEC;
/* Update the power resource's _device_ power state */
- device = resource->device;
- device->power.state = ACPI_STATE_D3;
+ resource->device->power.state = ACPI_STATE_D3;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
resource->name));
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 44c624bd40c..3e70a08e4a8 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -519,7 +519,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
static void *processor_device_array[NR_CPUS];
-static int acpi_processor_start(struct acpi_device *device)
+static int __cpuinit acpi_processor_start(struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 4504684671f..4f2982cc547 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -219,6 +219,23 @@ static void acpi_safe_halt(void)
static atomic_t c3_cpu_count;
+/* Common C-state entry for C2, C3, .. */
+static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
+{
+ if (cstate->space_id == ACPI_CSTATE_FFH) {
+ /* Call into architectural FFH based C-state */
+ acpi_processor_ffh_cstate_enter(cstate);
+ } else {
+ int unused;
+ /* IO port based C-state */
+ inb(cstate->address);
+ /* Dummy wait op - must do something useless after P_LVL2 read
+ because chipsets cannot guarantee that STPCLK# signal
+ gets asserted in time to freeze execution properly. */
+ unused = inl(acpi_fadt.xpm_tmr_blk.address);
+ }
+}
+
static void acpi_processor_idle(void)
{
struct acpi_processor *pr = NULL;
@@ -361,11 +378,7 @@ static void acpi_processor_idle(void)
/* Get start time (ticks) */
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Invoke C2 */
- inb(cx->address);
- /* Dummy wait op - must do something useless after P_LVL2 read
- because chipsets cannot guarantee that STPCLK# signal
- gets asserted in time to freeze execution properly. */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
@@ -401,9 +414,7 @@ static void acpi_processor_idle(void)
/* Get start time (ticks) */
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Invoke C3 */
- inb(cx->address);
- /* Dummy wait op (see above) */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
if (pr->flags.bm_check) {
@@ -628,20 +639,16 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
return 0;
}
-static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
+static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
{
-
- /* Zero initialize all the C-states info. */
- memset(pr->power.states, 0, sizeof(pr->power.states));
-
- /* set the first C-State to C1 */
- pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
-
- /* the C0 state only exists as a filler in our array,
- * and all processors need to support C1 */
+ if (!pr->power.states[ACPI_STATE_C1].valid) {
+ /* set the first C-State to C1 */
+ /* all processors need to support C1 */
+ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+ pr->power.states[ACPI_STATE_C1].valid = 1;
+ }
+ /* the C0 state only exists as a filler in our array */
pr->power.states[ACPI_STATE_C0].valid = 1;
- pr->power.states[ACPI_STATE_C1].valid = 1;
-
return 0;
}
@@ -658,12 +665,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
if (nocst)
return -ENODEV;
- current_count = 1;
-
- /* Zero initialize C2 onwards and prepare for fresh CST lookup */
- for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++)
- memset(&(pr->power.states[i]), 0,
- sizeof(struct acpi_processor_cx));
+ current_count = 0;
status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
@@ -718,22 +720,39 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
(reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
continue;
- cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
- 0 : reg->address;
-
/* There should be an easy way to extract an integer... */
obj = &(element->package.elements[1]);
if (obj->type != ACPI_TYPE_INTEGER)
continue;
cx.type = obj->integer.value;
-
- if ((cx.type != ACPI_STATE_C1) &&
- (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
- continue;
-
- if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
- continue;
+ /*
+ * Some buggy BIOSes won't list C1 in _CST -
+ * Let acpi_processor_get_power_info_default() handle them later
+ */
+ if (i == 1 && cx.type != ACPI_STATE_C1)
+ current_count++;
+
+ cx.address = reg->address;
+ cx.index = current_count + 1;
+
+ cx.space_id = ACPI_CSTATE_SYSTEMIO;
+ if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
+ if (acpi_processor_ffh_cstate_probe
+ (pr->id, &cx, reg) == 0) {
+ cx.space_id = ACPI_CSTATE_FFH;
+ } else if (cx.type != ACPI_STATE_C1) {
+ /*
+ * C1 is a special case where FIXED_HARDWARE
+ * can be handled in non-MWAIT way as well.
+ * In that case, save this _CST entry info.
+ * That is, we retain space_id of SYSTEM_IO for
+ * halt based C1.
+ * Otherwise, ignore this info and continue.
+ */
+ continue;
+ }
+ }
obj = &(element->package.elements[2]);
if (obj->type != ACPI_TYPE_INTEGER)
@@ -938,11 +957,17 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
/* NOTE: the idle thread may not be running while calling
* this function */
- /* Adding C1 state */
- acpi_processor_get_power_info_default_c1(pr);
+ /* Zero initialize all the C-states info. */
+ memset(pr->power.states, 0, sizeof(pr->power.states));
+
result = acpi_processor_get_power_info_cst(pr);
if (result == -ENODEV)
- acpi_processor_get_power_info_fadt(pr);
+ result = acpi_processor_get_power_info_fadt(pr);
+
+ if (result)
+ return result;
+
+ acpi_processor_get_power_info_default(pr);
pr->power.count = acpi_processor_power_verify(pr);
@@ -1083,6 +1108,7 @@ static const struct file_operations acpi_processor_power_fops = {
.release = single_release,
};
+#ifdef CONFIG_SMP
static void smp_callback(void *v)
{
/* we already woke the CPU up, nothing more to do */
@@ -1104,8 +1130,9 @@ static int acpi_processor_latency_notify(struct notifier_block *b,
static struct notifier_block acpi_processor_latency_notifier = {
.notifier_call = acpi_processor_latency_notify,
};
+#endif
-int acpi_processor_power_init(struct acpi_processor *pr,
+int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device)
{
acpi_status status = 0;
@@ -1121,7 +1148,9 @@ int acpi_processor_power_init(struct acpi_processor *pr,
"ACPI: processor limited to max C-state %d\n",
max_cstate);
first_run++;
+#ifdef CONFIG_SMP
register_latency_notifier(&acpi_processor_latency_notifier);
+#endif
}
if (!pr)
@@ -1193,7 +1222,9 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
* copies of pm_idle before proceeding.
*/
cpu_idle_wait();
+#ifdef CONFIG_SMP
unregister_latency_notifier(&acpi_processor_latency_notifier);
+#endif
}
return 0;
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 39fdbcc37d4..0e60382714b 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -83,10 +83,8 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
goto out;
ppc = (unsigned int)pr->performance_platform_limit;
- if (!ppc)
- goto out;
- if (ppc > pr->performance->state_count)
+ if (ppc >= pr->performance->state_count)
goto out;
cpufreq_verify_within_limits(policy, 0,
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index c6a819adcc9..2fb7533314c 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -98,11 +98,11 @@ static int update_info_mode = UPDATE_INFO_MODE;
static int update_time = UPDATE_TIME;
static int update_time2 = UPDATE_TIME2;
-module_param(capacity_mode, int, CAPACITY_UNIT);
-module_param(update_mode, int, UPDATE_MODE);
-module_param(update_info_mode, int, UPDATE_INFO_MODE);
-module_param(update_time, int, UPDATE_TIME);
-module_param(update_time2, int, UPDATE_TIME2);
+module_param(capacity_mode, int, 0);
+module_param(update_mode, int, 0);
+module_param(update_info_mode, int, 0);
+module_param(update_time, int, 0);
+module_param(update_time2, int, 0);
static int acpi_sbs_add(struct acpi_device *device);
static int acpi_sbs_remove(struct acpi_device *device, int type);
@@ -1685,10 +1685,16 @@ static int acpi_sbs_add(struct acpi_device *device)
int acpi_sbs_remove(struct acpi_device *device, int type)
{
- struct acpi_sbs *sbs = acpi_driver_data(device);
+ struct acpi_sbs *sbs;
int id;
- if (!device || !sbs) {
+ if (!device) {
+ return -EINVAL;
+ }
+
+ sbs = (struct acpi_sbs *)acpi_driver_data(device);
+
+ if (!sbs) {
return -EINVAL;
}
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
index af1dbabaf0b..fab8f2694f0 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/sleep/wakeup.c
@@ -183,11 +183,11 @@ late_initcall(acpi_wakeup_device_init);
#endif
/*
- * Disable all wakeup GPEs before power off.
- *
+ * Disable all wakeup GPEs before entering requested sleep state.
+ * @sleep_state: ACPI state
* Since acpi_enter_sleep_state() will disable all
* RUNTIME GPEs, we simply mark all GPES that
- * are not enabled for wakeup from S5 as RUNTIME.
+ * are not enabled for wakeup from requested state as RUNTIME.
*/
void acpi_gpe_sleep_prepare(u32 sleep_state)
{
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
index 7856db759af..11e2d4454e0 100644
--- a/drivers/acpi/tables/tbget.c
+++ b/drivers/acpi/tables/tbget.c
@@ -324,7 +324,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
if (header->length < sizeof(struct acpi_table_header)) {
ACPI_ERROR((AE_INFO,
- "Table length (%X) is smaller than minimum (%X)",
+ "Table length (%X) is smaller than minimum (%zX)",
header->length, sizeof(struct acpi_table_header)));
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
index 0ad3dbb9ebc..86a5fca9b73 100644
--- a/drivers/acpi/tables/tbrsdt.c
+++ b/drivers/acpi/tables/tbrsdt.c
@@ -187,7 +187,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
if (table_ptr->length < sizeof(struct acpi_table_header)) {
ACPI_ERROR((AE_INFO,
- "RSDT/XSDT length (%X) is smaller than minimum (%X)",
+ "RSDT/XSDT length (%X) is smaller than minimum (%zX)",
table_ptr->length,
sizeof(struct acpi_table_header)));
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index 7fe0b7ae973..2f35f891593 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -41,6 +41,8 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+
#include <asm/uaccess.h>
#include <acpi/acpi_drivers.h>
@@ -210,6 +212,7 @@ static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
}
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
+static struct backlight_device *toshiba_backlight_device;
static int force_fan;
static int last_key_event;
static int key_event_valid;
@@ -271,14 +274,23 @@ dispatch_write(struct file *file, const char __user * buffer,
return result;
}
-static char *read_lcd(char *p)
+static int get_lcd(struct backlight_device *bd)
{
u32 hci_result;
u32 value;
hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
if (hci_result == HCI_SUCCESS) {
- value = value >> HCI_LCD_BRIGHTNESS_SHIFT;
+ return (value >> HCI_LCD_BRIGHTNESS_SHIFT);
+ } else
+ return -EFAULT;
+}
+
+static char *read_lcd(char *p)
+{
+ int value = get_lcd(NULL);
+
+ if (value >= 0) {
p += sprintf(p, "brightness: %d\n", value);
p += sprintf(p, "brightness_levels: %d\n",
HCI_LCD_BRIGHTNESS_LEVELS);
@@ -289,22 +301,34 @@ static char *read_lcd(char *p)
return p;
}
+static int set_lcd(int value)
+{
+ u32 hci_result;
+
+ value = value << HCI_LCD_BRIGHTNESS_SHIFT;
+ hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
+ if (hci_result != HCI_SUCCESS)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int set_lcd_status(struct backlight_device *bd)
+{
+ return set_lcd(bd->props->brightness);
+}
+
static unsigned long write_lcd(const char *buffer, unsigned long count)
{
int value;
- u32 hci_result;
+ int ret = count;
if (sscanf(buffer, " brightness : %i", &value) == 1 &&
- value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
- value = value << HCI_LCD_BRIGHTNESS_SHIFT;
- hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
- if (hci_result != HCI_SUCCESS)
- return -EFAULT;
- } else {
- return -EINVAL;
- }
-
- return count;
+ value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS)
+ ret = set_lcd(value);
+ else
+ ret = -EINVAL;
+ return ret;
}
static char *read_video(char *p)
@@ -506,6 +530,26 @@ static acpi_status __exit remove_device(void)
return AE_OK;
}
+static struct backlight_properties toshiba_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = get_lcd,
+ .update_status = set_lcd_status,
+ .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1,
+};
+
+static void __exit toshiba_acpi_exit(void)
+{
+ if (toshiba_backlight_device)
+ backlight_device_unregister(toshiba_backlight_device);
+
+ remove_device();
+
+ if (toshiba_proc_dir)
+ remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+
+ return;
+}
+
static int __init toshiba_acpi_init(void)
{
acpi_status status = AE_OK;
@@ -546,17 +590,15 @@ static int __init toshiba_acpi_init(void)
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
}
- return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
-}
-
-static void __exit toshiba_acpi_exit(void)
-{
- remove_device();
-
- if (toshiba_proc_dir)
- remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+ toshiba_backlight_device = backlight_device_register("toshiba", NULL,
+ &toshiba_backlight_data);
+ if (IS_ERR(toshiba_backlight_device)) {
+ printk(KERN_ERR "Could not register toshiba backlight device\n");
+ toshiba_backlight_device = NULL;
+ toshiba_acpi_exit();
+ }
- return;
+ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
}
module_init(toshiba_acpi_init);
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index bb1eaf9aa65..9e9054e155c 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -180,8 +180,9 @@ acpi_ut_debug_print(u32 requested_debug_level,
if (thread_id != acpi_gbl_prev_thread_id) {
if (ACPI_LV_THREADS & acpi_dbg_level) {
acpi_os_printf
- ("\n**** Context Switch from TID %X to TID %X ****\n\n",
- (u32) acpi_gbl_prev_thread_id, (u32) thread_id);
+ ("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
+ (unsigned long) acpi_gbl_prev_thread_id,
+ (unsigned long) thread_id);
}
acpi_gbl_prev_thread_id = thread_id;
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index c39062a047c..180e73ceb6e 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -243,23 +243,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
#endif
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X attempting to acquire Mutex [%s]\n",
- (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id)));
+ "Thread %lX attempting to acquire Mutex [%s]\n",
+ (unsigned long) this_thread_id,
+ acpi_ut_get_mutex_name(mutex_id)));
status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
ACPI_WAIT_FOREVER);
if (ACPI_SUCCESS(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X acquired Mutex [%s]\n",
- (u32) this_thread_id,
+ "Thread %lX acquired Mutex [%s]\n",
+ (unsigned long) this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
acpi_gbl_mutex_info[mutex_id].use_count++;
acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
} else {
ACPI_EXCEPTION((AE_INFO, status,
- "Thread %X could not acquire Mutex [%X]",
- (u32) this_thread_id, mutex_id));
+ "Thread %lX could not acquire Mutex [%X]",
+ (unsigned long) this_thread_id, mutex_id));
}
return (status);
@@ -285,7 +286,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
this_thread_id = acpi_os_get_thread_id();
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id,
+ "Thread %lX releasing Mutex [%s]\n",
+ (unsigned long) this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
if (mutex_id > ACPI_MAX_MUTEX) {