summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/acpi_video.c3
-rw-r--r--drivers/acpi/button.c149
-rw-r--r--drivers/acpi/ec.c106
-rw-r--r--drivers/acpi/thermal.c3
-rw-r--r--drivers/acpi/video_detect.c8
-rw-r--r--include/acpi/video.h2
6 files changed, 174 insertions, 97 deletions
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index c1d138e128cb..c5557d070954 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -1246,6 +1246,9 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
union acpi_object *dod = NULL;
union acpi_object *obj;
+ if (!video->cap._DOD)
+ return AE_NOT_EXIST;
+
status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
if (!ACPI_SUCCESS(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 5c3b0918d5fd..148f4e5ca104 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -53,6 +53,10 @@
#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
#define ACPI_BUTTON_TYPE_LID 0x05
+#define ACPI_BUTTON_LID_INIT_IGNORE 0x00
+#define ACPI_BUTTON_LID_INIT_OPEN 0x01
+#define ACPI_BUTTON_LID_INIT_METHOD 0x02
+
#define _COMPONENT ACPI_BUTTON_COMPONENT
ACPI_MODULE_NAME("button");
@@ -105,6 +109,7 @@ struct acpi_button {
static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
static struct acpi_device *lid_device;
+static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
/* --------------------------------------------------------------------------
FS Interface (/proc)
@@ -113,16 +118,52 @@ static struct acpi_device *lid_device;
static struct proc_dir_entry *acpi_button_dir;
static struct proc_dir_entry *acpi_lid_dir;
+static int acpi_lid_evaluate_state(struct acpi_device *device)
+{
+ unsigned long long lid_state;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(device->handle, "_LID", NULL, &lid_state);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ return lid_state ? 1 : 0;
+}
+
+static int acpi_lid_notify_state(struct acpi_device *device, int state)
+{
+ struct acpi_button *button = acpi_driver_data(device);
+ int ret;
+
+ /* input layer checks if event is redundant */
+ input_report_switch(button->input, SW_LID, !state);
+ input_sync(button->input);
+
+ if (state)
+ pm_wakeup_event(&device->dev, 0);
+
+ ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
+ if (ret == NOTIFY_DONE)
+ ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
+ device);
+ if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
+ /*
+ * It is also regarded as success if the notifier_chain
+ * returns NOTIFY_OK or NOTIFY_DONE.
+ */
+ ret = 0;
+ }
+ return ret;
+}
+
static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_device *device = seq->private;
- acpi_status status;
- unsigned long long state;
+ int state;
- status = acpi_evaluate_integer(device->handle, "_LID", NULL, &state);
+ state = acpi_lid_evaluate_state(device);
seq_printf(seq, "state: %s\n",
- ACPI_FAILURE(status) ? "unsupported" :
- (state ? "open" : "closed"));
+ state < 0 ? "unsupported" : (state ? "open" : "closed"));
return 0;
}
@@ -231,51 +272,37 @@ EXPORT_SYMBOL(acpi_lid_notifier_unregister);
int acpi_lid_open(void)
{
- acpi_status status;
- unsigned long long state;
-
if (!lid_device)
return -ENODEV;
- status = acpi_evaluate_integer(lid_device->handle, "_LID", NULL,
- &state);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- return !!state;
+ return acpi_lid_evaluate_state(lid_device);
}
EXPORT_SYMBOL(acpi_lid_open);
-static int acpi_lid_send_state(struct acpi_device *device)
+static int acpi_lid_update_state(struct acpi_device *device)
{
- struct acpi_button *button = acpi_driver_data(device);
- unsigned long long state;
- acpi_status status;
- int ret;
-
- status = acpi_evaluate_integer(device->handle, "_LID", NULL, &state);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ int state;
- /* input layer checks if event is redundant */
- input_report_switch(button->input, SW_LID, !state);
- input_sync(button->input);
+ state = acpi_lid_evaluate_state(device);
+ if (state < 0)
+ return state;
- if (state)
- pm_wakeup_event(&device->dev, 0);
+ return acpi_lid_notify_state(device, state);
+}
- ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
- if (ret == NOTIFY_DONE)
- ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
- device);
- if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
- /*
- * It is also regarded as success if the notifier_chain
- * returns NOTIFY_OK or NOTIFY_DONE.
- */
- ret = 0;
+static void acpi_lid_initialize_state(struct acpi_device *device)
+{
+ switch (lid_init_state) {
+ case ACPI_BUTTON_LID_INIT_OPEN:
+ (void)acpi_lid_notify_state(device, 1);
+ break;
+ case ACPI_BUTTON_LID_INIT_METHOD:
+ (void)acpi_lid_update_state(device);
+ break;
+ case ACPI_BUTTON_LID_INIT_IGNORE:
+ default:
+ break;
}
- return ret;
}
static void acpi_button_notify(struct acpi_device *device, u32 event)
@@ -290,7 +317,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
case ACPI_BUTTON_NOTIFY_STATUS:
input = button->input;
if (button->type == ACPI_BUTTON_TYPE_LID) {
- acpi_lid_send_state(device);
+ acpi_lid_update_state(device);
} else {
int keycode;
@@ -335,7 +362,7 @@ static int acpi_button_resume(struct device *dev)
button->suspended = false;
if (button->type == ACPI_BUTTON_TYPE_LID)
- return acpi_lid_send_state(device);
+ acpi_lid_initialize_state(device);
return 0;
}
#endif
@@ -416,7 +443,7 @@ static int acpi_button_add(struct acpi_device *device)
if (error)
goto err_remove_fs;
if (button->type == ACPI_BUTTON_TYPE_LID) {
- acpi_lid_send_state(device);
+ acpi_lid_initialize_state(device);
/*
* This assumes there's only one lid device, or if there are
* more we only care about the last one...
@@ -446,4 +473,42 @@ static int acpi_button_remove(struct acpi_device *device)
return 0;
}
+static int param_set_lid_init_state(const char *val, struct kernel_param *kp)
+{
+ int result = 0;
+
+ if (!strncmp(val, "open", sizeof("open") - 1)) {
+ lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
+ pr_info("Notify initial lid state as open\n");
+ } else if (!strncmp(val, "method", sizeof("method") - 1)) {
+ lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
+ pr_info("Notify initial lid state with _LID return value\n");
+ } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
+ lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
+ pr_info("Do not notify initial lid state\n");
+ } else
+ result = -EINVAL;
+ return result;
+}
+
+static int param_get_lid_init_state(char *buffer, struct kernel_param *kp)
+{
+ switch (lid_init_state) {
+ case ACPI_BUTTON_LID_INIT_OPEN:
+ return sprintf(buffer, "open");
+ case ACPI_BUTTON_LID_INIT_METHOD:
+ return sprintf(buffer, "method");
+ case ACPI_BUTTON_LID_INIT_IGNORE:
+ return sprintf(buffer, "ignore");
+ default:
+ return sprintf(buffer, "invalid");
+ }
+ return 0;
+}
+
+module_param_call(lid_init_state,
+ param_set_lid_init_state, param_get_lid_init_state,
+ NULL, 0644);
+MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state");
+
module_acpi_driver(acpi_button_driver);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 290d6f5be44b..999a10914678 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1359,13 +1359,9 @@ static void ec_remove_handlers(struct acpi_ec *ec)
}
}
-static int acpi_ec_add(struct acpi_device *device)
+static struct acpi_ec *acpi_ec_alloc(void)
{
- struct acpi_ec *ec = NULL;
- int ret;
-
- strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_EC_CLASS);
+ struct acpi_ec *ec;
/* Check for boot EC */
if (boot_ec) {
@@ -1376,9 +1372,21 @@ static int acpi_ec_add(struct acpi_device *device)
first_ec = NULL;
} else {
ec = make_acpi_ec();
- if (!ec)
- return -ENOMEM;
}
+ return ec;
+}
+
+static int acpi_ec_add(struct acpi_device *device)
+{
+ struct acpi_ec *ec = NULL;
+ int ret;
+
+ strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_EC_CLASS);
+
+ ec = acpi_ec_alloc();
+ if (!ec)
+ return -ENOMEM;
if (ec_parse_device(device->handle, 0, ec, NULL) !=
AE_CTRL_TERMINATE) {
kfree(ec);
@@ -1465,27 +1473,31 @@ static const struct acpi_device_id ec_device_ids[] = {
int __init acpi_ec_dsdt_probe(void)
{
acpi_status status;
+ struct acpi_ec *ec;
+ int ret;
- if (boot_ec)
- return 0;
-
+ ec = acpi_ec_alloc();
+ if (!ec)
+ return -ENOMEM;
/*
* Finding EC from DSDT if there is no ECDT EC available. When this
* function is invoked, ACPI tables have been fully loaded, we can
* walk namespace now.
*/
- boot_ec = make_acpi_ec();
- if (!boot_ec)
- return -ENOMEM;
status = acpi_get_devices(ec_device_ids[0].id,
- ec_parse_device, boot_ec, NULL);
- if (ACPI_FAILURE(status) || !boot_ec->handle)
- return -ENODEV;
- if (!ec_install_handlers(boot_ec)) {
- first_ec = boot_ec;
- return 0;
+ ec_parse_device, ec, NULL);
+ if (ACPI_FAILURE(status) || !ec->handle) {
+ ret = -ENODEV;
+ goto error;
}
- return -EFAULT;
+ ret = ec_install_handlers(ec);
+
+error:
+ if (ret)
+ kfree(ec);
+ else
+ first_ec = boot_ec = ec;
+ return ret;
}
#if 0
@@ -1529,6 +1541,11 @@ static int ec_clear_on_resume(const struct dmi_system_id *id)
return 0;
}
+/*
+ * Some ECDTs contain wrong register addresses.
+ * MSI MS-171F
+ * https://bugzilla.kernel.org/show_bug.cgi?id=12461
+ */
static int ec_correct_ecdt(const struct dmi_system_id *id)
{
pr_debug("Detected system needing ECDT address correction.\n");
@@ -1538,16 +1555,6 @@ static int ec_correct_ecdt(const struct dmi_system_id *id)
static struct dmi_system_id ec_dmi_table[] __initdata = {
{
- ec_correct_ecdt, "Asus L4R", {
- DMI_MATCH(DMI_BIOS_VERSION, "1008.006"),
- DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),
- DMI_MATCH(DMI_BOARD_NAME, "L4R") }, NULL},
- {
- ec_correct_ecdt, "Asus M6R", {
- DMI_MATCH(DMI_BIOS_VERSION, "0207"),
- DMI_MATCH(DMI_PRODUCT_NAME, "M6R"),
- DMI_MATCH(DMI_BOARD_NAME, "M6R") }, NULL},
- {
ec_correct_ecdt, "MSI MS-171F", {
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
@@ -1559,12 +1566,13 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
int __init acpi_ec_ecdt_probe(void)
{
- int ret = 0;
+ int ret;
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
+ struct acpi_ec *ec;
- boot_ec = make_acpi_ec();
- if (!boot_ec)
+ ec = acpi_ec_alloc();
+ if (!ec)
return -ENOMEM;
/*
* Generate a boot ec context
@@ -1588,28 +1596,20 @@ int __init acpi_ec_ecdt_probe(void)
pr_info("EC description table is found, configuring boot EC\n");
if (EC_FLAGS_CORRECT_ECDT) {
- /*
- * Asus L4R, Asus M6R
- * https://bugzilla.kernel.org/show_bug.cgi?id=9399
- * MSI MS-171F
- * https://bugzilla.kernel.org/show_bug.cgi?id=12461
- */
- boot_ec->command_addr = ecdt_ptr->data.address;
- boot_ec->data_addr = ecdt_ptr->control.address;
+ ec->command_addr = ecdt_ptr->data.address;
+ ec->data_addr = ecdt_ptr->control.address;
} else {
- boot_ec->command_addr = ecdt_ptr->control.address;
- boot_ec->data_addr = ecdt_ptr->data.address;
+ ec->command_addr = ecdt_ptr->control.address;
+ ec->data_addr = ecdt_ptr->data.address;
}
- boot_ec->gpe = ecdt_ptr->gpe;
- boot_ec->handle = ACPI_ROOT_OBJECT;
- ret = ec_install_handlers(boot_ec);
- if (!ret)
- first_ec = boot_ec;
+ ec->gpe = ecdt_ptr->gpe;
+ ec->handle = ACPI_ROOT_OBJECT;
+ ret = ec_install_handlers(ec);
error:
- if (ret) {
- kfree(boot_ec);
- boot_ec = NULL;
- }
+ if (ret)
+ kfree(ec);
+ else
+ first_ec = boot_ec = ec;
return ret;
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 82707f9824ca..f4ebe39539af 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -1259,7 +1259,8 @@ static int __init acpi_thermal_init(void)
return -ENODEV;
}
- acpi_thermal_pm_queue = create_workqueue("acpi_thermal_pm");
+ acpi_thermal_pm_queue = alloc_workqueue("acpi_thermal_pm",
+ WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
if (!acpi_thermal_pm_queue)
return -ENODEV;
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 3d1327615f72..a6b36fc53aec 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -167,6 +167,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
},
},
+ {
+ .callback = video_detect_force_video,
+ .ident = "ThinkPad X201T",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"),
+ },
+ },
/* The native backlight controls do not work on some older machines */
{
diff --git a/include/acpi/video.h b/include/acpi/video.h
index 5731ccb42585..4536bd345ab4 100644
--- a/include/acpi/video.h
+++ b/include/acpi/video.h
@@ -54,7 +54,7 @@ extern int acpi_video_get_levels(struct acpi_device *device,
struct acpi_video_device_brightness **dev_br,
int *pmax_level);
#else
-static inline int acpi_video_register(void) { return 0; }
+static inline int acpi_video_register(void) { return -ENODEV; }
static inline void acpi_video_unregister(void) { return; }
static inline int acpi_video_get_edid(struct acpi_device *device, int type,
int device_id, void **edid)