From: Aaron Lu <aaron.lu@intel.com>
To: "Rafael J. Wysocki" <rjw@sisk.pl>, i-tek@web.de
Cc: Igor Murzov <intergalactic.anonymous@gmail.com>,
ACPI Devel Mailing List <linux-acpi@vger.kernel.org>,
Zhang Rui <rui.zhang@intel.com>
Subject: [PATCH] acpi: video: correct acpi_video_bus_add error processing
Date: Thu, 25 Apr 2013 10:47:49 +0800 [thread overview]
Message-ID: <51789955.5050304@intel.com> (raw)
acpi_video_bus_get_devices may fail due to some video output device
doesn't have the _ADR method, and in this case, the error processing is
to simply free the video structure in acpi_video_bus_add, while leaving
those already registered video output devices in the wild, which means
for some video output device, we have already registered a backlight
interface and installed a notification handler for it. So it can happen
when user is using this system, on hotkey pressing, the notification
handler will send a keycode through a non-existing input device, causing
kernel freeze.
To solve this problem, we free all those already registered video output
devices once something goes wrong in acpi_video_bus_get_devices so that
no wild backlight interfaces and notification handlers exist.
Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=51731
Reported-bisected-and-tested-by: <i-tek@web.de>
Signed-off-by: Aaron Lu <aaron.lu@intel.com>
---
drivers/acpi/video.c | 143 ++++++++++++++++++++++++---------------------------
1 file changed, 66 insertions(+), 77 deletions(-)
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index ed192e5..c3932d0 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -167,7 +167,8 @@ struct acpi_video_device_flags {
u8 dvi:1;
u8 bios:1;
u8 unknown:1;
- u8 reserved:2;
+ u8 notify:1;
+ u8 reserved:1;
};
struct acpi_video_device_cap {
@@ -1074,53 +1075,51 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
struct acpi_video_device *data;
struct acpi_video_device_attrib* attribute;
- if (!device || !video)
- return -EINVAL;
-
status =
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
- if (ACPI_SUCCESS(status)) {
-
- data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
- device->driver_data = data;
-
- data->device_id = device_id;
- data->video = video;
- data->dev = device;
+ /* Some device omits _ADR, we skip them instead of fail */
+ if (ACPI_FAILURE(status))
+ return 0;
- attribute = acpi_video_get_device_attr(video, device_id);
+ data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- if((attribute != NULL) && attribute->device_id_scheme) {
- switch (attribute->display_type) {
- case ACPI_VIDEO_DISPLAY_CRT:
- data->flags.crt = 1;
- break;
- case ACPI_VIDEO_DISPLAY_TV:
- data->flags.tvout = 1;
- break;
- case ACPI_VIDEO_DISPLAY_DVI:
- data->flags.dvi = 1;
- break;
- case ACPI_VIDEO_DISPLAY_LCD:
- data->flags.lcd = 1;
- break;
- default:
- data->flags.unknown = 1;
- break;
- }
- if(attribute->bios_can_detect)
- data->flags.bios = 1;
- } else {
- /* Check for legacy IDs */
- device_type = acpi_video_get_device_type(video,
- device_id);
- /* Ignore bits 16 and 18-20 */
- switch (device_type & 0xffe2ffff) {
+ strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
+ device->driver_data = data;
+
+ data->device_id = device_id;
+ data->video = video;
+ data->dev = device;
+
+ attribute = acpi_video_get_device_attr(video, device_id);
+
+ if((attribute != NULL) && attribute->device_id_scheme) {
+ switch (attribute->display_type) {
+ case ACPI_VIDEO_DISPLAY_CRT:
+ data->flags.crt = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_TV:
+ data->flags.tvout = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_DVI:
+ data->flags.dvi = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LCD:
+ data->flags.lcd = 1;
+ break;
+ default:
+ data->flags.unknown = 1;
+ break;
+ }
+ if(attribute->bios_can_detect)
+ data->flags.bios = 1;
+ } else {
+ /* Check for legacy IDs */
+ device_type = acpi_video_get_device_type(video, device_id);
+ /* Ignore bits 16 and 18-20 */
+ switch (device_type & 0xffe2ffff) {
case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
data->flags.crt = 1;
break;
@@ -1132,34 +1131,24 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
break;
default:
data->flags.unknown = 1;
- }
}
+ }
- acpi_video_device_bind(video, data);
- acpi_video_device_find_cap(data);
-
- status = acpi_install_notify_handler(device->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_video_device_notify,
- data);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX
- "Error installing notify handler\n");
- if(data->brightness)
- kfree(data->brightness->levels);
- kfree(data->brightness);
- kfree(data);
- return -ENODEV;
- }
+ acpi_video_device_bind(video, data);
+ acpi_video_device_find_cap(data);
- mutex_lock(&video->device_list_lock);
- list_add_tail(&data->entry, &video->video_device_list);
- mutex_unlock(&video->device_list_lock);
+ status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+ acpi_video_device_notify, data);
+ if (ACPI_FAILURE(status))
+ dev_err(&device->dev, "Error installing notify handler\n");
+ else
+ data->flags.notify = 1;
- return 0;
- }
+ mutex_lock(&video->device_list_lock);
+ list_add_tail(&data->entry, &video->video_device_list);
+ mutex_unlock(&video->device_list_lock);
- return -ENOENT;
+ return status;
}
/*
@@ -1452,9 +1441,8 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
status = acpi_video_bus_get_one_device(dev, video);
if (status) {
- printk(KERN_WARNING PREFIX
- "Can't attach device\n");
- continue;
+ dev_err(&dev->dev, "Can't attach device\n");
+ break;
}
}
return status;
@@ -1467,13 +1455,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
if (!device || !device->video)
return -ENOENT;
- status = acpi_remove_notify_handler(device->dev->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_video_device_notify);
- if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING PREFIX
- "Can't remove video notify handler\n");
+ if (device->flags.notify) {
+ status = acpi_remove_notify_handler(device->dev->handle,
+ ACPI_DEVICE_NOTIFY, acpi_video_device_notify);
+ if (ACPI_FAILURE(status))
+ dev_err(&device->dev->dev,
+ "Can't remove video notify handler\n");
}
+
if (device->backlight) {
backlight_device_unregister(device->backlight);
device->backlight = NULL;
@@ -1755,7 +1744,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
error = acpi_video_bus_get_devices(video, device);
if (error)
- goto err_free_video;
+ goto err_put_video;
video->input = input = input_allocate_device();
if (!input) {
--
1.8.2.1
next reply other threads:[~2013-04-25 2:46 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-25 2:47 Aaron Lu [this message]
2013-04-25 11:03 ` [PATCH] acpi: video: correct acpi_video_bus_add error processing Rafael J. Wysocki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51789955.5050304@intel.com \
--to=aaron.lu@intel.com \
--cc=i-tek@web.de \
--cc=intergalactic.anonymous@gmail.com \
--cc=linux-acpi@vger.kernel.org \
--cc=rjw@sisk.pl \
--cc=rui.zhang@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.