public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
From: "Rafael J. Wysocki" <rjw@sisk.pl>
To: Aaron Lu <aaron.lu@intel.com>
Cc: i-tek@web.de, Igor Murzov <intergalactic.anonymous@gmail.com>,
	ACPI Devel Mailing List <linux-acpi@vger.kernel.org>,
	Zhang Rui <rui.zhang@intel.com>
Subject: Re: [PATCH] acpi: video: correct acpi_video_bus_add error processing
Date: Thu, 25 Apr 2013 13:03:04 +0200	[thread overview]
Message-ID: <2845639.6IhJslDaKz@vostro.rjw.lan> (raw)
In-Reply-To: <51789955.5050304@intel.com>

On Thursday, April 25, 2013 10:47:49 AM Aaron Lu wrote:
> 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>

Applied.

Thanks,
Rafael


> ---
>  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) {
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

      reply	other threads:[~2013-04-25 10:54 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-25  2:47 [PATCH] acpi: video: correct acpi_video_bus_add error processing Aaron Lu
2013-04-25 11:03 ` Rafael J. Wysocki [this message]

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=2845639.6IhJslDaKz@vostro.rjw.lan \
    --to=rjw@sisk.pl \
    --cc=aaron.lu@intel.com \
    --cc=i-tek@web.de \
    --cc=intergalactic.anonymous@gmail.com \
    --cc=linux-acpi@vger.kernel.org \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox