aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/video.c
diff options
context:
space:
mode:
authorAaron Lu <aaron.lu@intel.com>2013-04-24 22:47:49 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-04-25 06:53:19 -0400
commit91e13aa37023437c260c85a3f17308052bbfbfa2 (patch)
treec867075f3975ca0d3611e99c5be6f102da55f326 /drivers/acpi/video.c
parenta6432ded299726f123b93d0132fead200551535c (diff)
ACPI: video: correct acpi_video_bus_add error processing
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, 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. References: https://bugzilla.kernel.org/show_bug.cgi?id=51731 Reported-and-tested-by: <i-tek@web.de> Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r--drivers/acpi/video.c143
1 files changed, 66 insertions, 77 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index ed192e5d82b6..c3932d0876e0 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -167,7 +167,8 @@ struct acpi_video_device_flags {
167 u8 dvi:1; 167 u8 dvi:1;
168 u8 bios:1; 168 u8 bios:1;
169 u8 unknown:1; 169 u8 unknown:1;
170 u8 reserved:2; 170 u8 notify:1;
171 u8 reserved:1;
171}; 172};
172 173
173struct acpi_video_device_cap { 174struct acpi_video_device_cap {
@@ -1074,53 +1075,51 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
1074 struct acpi_video_device *data; 1075 struct acpi_video_device *data;
1075 struct acpi_video_device_attrib* attribute; 1076 struct acpi_video_device_attrib* attribute;
1076 1077
1077 if (!device || !video)
1078 return -EINVAL;
1079
1080 status = 1078 status =
1081 acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); 1079 acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
1082 if (ACPI_SUCCESS(status)) { 1080 /* Some device omits _ADR, we skip them instead of fail */
1083 1081 if (ACPI_FAILURE(status))
1084 data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL); 1082 return 0;
1085 if (!data)
1086 return -ENOMEM;
1087
1088 strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
1089 strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1090 device->driver_data = data;
1091
1092 data->device_id = device_id;
1093 data->video = video;
1094 data->dev = device;
1095 1083
1096 attribute = acpi_video_get_device_attr(video, device_id); 1084 data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
1085 if (!data)
1086 return -ENOMEM;
1097 1087
1098 if((attribute != NULL) && attribute->device_id_scheme) { 1088 strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
1099 switch (attribute->display_type) { 1089 strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1100 case ACPI_VIDEO_DISPLAY_CRT: 1090 device->driver_data = data;
1101 data->flags.crt = 1; 1091
1102 break; 1092 data->device_id = device_id;
1103 case ACPI_VIDEO_DISPLAY_TV: 1093 data->video = video;
1104 data->flags.tvout = 1; 1094 data->dev = device;
1105 break; 1095
1106 case ACPI_VIDEO_DISPLAY_DVI: 1096 attribute = acpi_video_get_device_attr(video, device_id);
1107 data->flags.dvi = 1; 1097
1108 break; 1098 if((attribute != NULL) && attribute->device_id_scheme) {
1109 case ACPI_VIDEO_DISPLAY_LCD: 1099 switch (attribute->display_type) {
1110 data->flags.lcd = 1; 1100 case ACPI_VIDEO_DISPLAY_CRT:
1111 break; 1101 data->flags.crt = 1;
1112 default: 1102 break;
1113 data->flags.unknown = 1; 1103 case ACPI_VIDEO_DISPLAY_TV:
1114 break; 1104 data->flags.tvout = 1;
1115 } 1105 break;
1116 if(attribute->bios_can_detect) 1106 case ACPI_VIDEO_DISPLAY_DVI:
1117 data->flags.bios = 1; 1107 data->flags.dvi = 1;
1118 } else { 1108 break;
1119 /* Check for legacy IDs */ 1109 case ACPI_VIDEO_DISPLAY_LCD:
1120 device_type = acpi_video_get_device_type(video, 1110 data->flags.lcd = 1;
1121 device_id); 1111 break;
1122 /* Ignore bits 16 and 18-20 */ 1112 default:
1123 switch (device_type & 0xffe2ffff) { 1113 data->flags.unknown = 1;
1114 break;
1115 }
1116 if(attribute->bios_can_detect)
1117 data->flags.bios = 1;
1118 } else {
1119 /* Check for legacy IDs */
1120 device_type = acpi_video_get_device_type(video, device_id);
1121 /* Ignore bits 16 and 18-20 */
1122 switch (device_type & 0xffe2ffff) {
1124 case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR: 1123 case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
1125 data->flags.crt = 1; 1124 data->flags.crt = 1;
1126 break; 1125 break;
@@ -1132,34 +1131,24 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
1132 break; 1131 break;
1133 default: 1132 default:
1134 data->flags.unknown = 1; 1133 data->flags.unknown = 1;
1135 }
1136 } 1134 }
1135 }
1137 1136
1138 acpi_video_device_bind(video, data); 1137 acpi_video_device_bind(video, data);
1139 acpi_video_device_find_cap(data); 1138 acpi_video_device_find_cap(data);
1140
1141 status = acpi_install_notify_handler(device->handle,
1142 ACPI_DEVICE_NOTIFY,
1143 acpi_video_device_notify,
1144 data);
1145 if (ACPI_FAILURE(status)) {
1146 printk(KERN_ERR PREFIX
1147 "Error installing notify handler\n");
1148 if(data->brightness)
1149 kfree(data->brightness->levels);
1150 kfree(data->brightness);
1151 kfree(data);
1152 return -ENODEV;
1153 }
1154 1139
1155 mutex_lock(&video->device_list_lock); 1140 status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
1156 list_add_tail(&data->entry, &video->video_device_list); 1141 acpi_video_device_notify, data);
1157 mutex_unlock(&video->device_list_lock); 1142 if (ACPI_FAILURE(status))
1143 dev_err(&device->dev, "Error installing notify handler\n");
1144 else
1145 data->flags.notify = 1;
1158 1146
1159 return 0; 1147 mutex_lock(&video->device_list_lock);
1160 } 1148 list_add_tail(&data->entry, &video->video_device_list);
1149 mutex_unlock(&video->device_list_lock);
1161 1150
1162 return -ENOENT; 1151 return status;
1163} 1152}
1164 1153
1165/* 1154/*
@@ -1452,9 +1441,8 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
1452 1441
1453 status = acpi_video_bus_get_one_device(dev, video); 1442 status = acpi_video_bus_get_one_device(dev, video);
1454 if (status) { 1443 if (status) {
1455 printk(KERN_WARNING PREFIX 1444 dev_err(&dev->dev, "Can't attach device\n");
1456 "Can't attach device\n"); 1445 break;
1457 continue;
1458 } 1446 }
1459 } 1447 }
1460 return status; 1448 return status;
@@ -1467,13 +1455,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
1467 if (!device || !device->video) 1455 if (!device || !device->video)
1468 return -ENOENT; 1456 return -ENOENT;
1469 1457
1470 status = acpi_remove_notify_handler(device->dev->handle, 1458 if (device->flags.notify) {
1471 ACPI_DEVICE_NOTIFY, 1459 status = acpi_remove_notify_handler(device->dev->handle,
1472 acpi_video_device_notify); 1460 ACPI_DEVICE_NOTIFY, acpi_video_device_notify);
1473 if (ACPI_FAILURE(status)) { 1461 if (ACPI_FAILURE(status))
1474 printk(KERN_WARNING PREFIX 1462 dev_err(&device->dev->dev,
1475 "Can't remove video notify handler\n"); 1463 "Can't remove video notify handler\n");
1476 } 1464 }
1465
1477 if (device->backlight) { 1466 if (device->backlight) {
1478 backlight_device_unregister(device->backlight); 1467 backlight_device_unregister(device->backlight);
1479 device->backlight = NULL; 1468 device->backlight = NULL;
@@ -1755,7 +1744,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
1755 1744
1756 error = acpi_video_bus_get_devices(video, device); 1745 error = acpi_video_bus_get_devices(video, device);
1757 if (error) 1746 if (error)
1758 goto err_free_video; 1747 goto err_put_video;
1759 1748
1760 video->input = input = input_allocate_device(); 1749 video->input = input = input_allocate_device();
1761 if (!input) { 1750 if (!input) {