|
@@ -73,8 +73,12 @@ MODULE_AUTHOR("Bruno Ducrot");
|
|
|
MODULE_DESCRIPTION("ACPI Video Driver");
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|
|
+static int brightness_switch_enabled = 1;
|
|
|
+module_param(brightness_switch_enabled, bool, 0644);
|
|
|
+
|
|
|
static int acpi_video_bus_add(struct acpi_device *device);
|
|
|
static int acpi_video_bus_remove(struct acpi_device *device, int type);
|
|
|
+static int acpi_video_resume(struct acpi_device *device);
|
|
|
|
|
|
static const struct acpi_device_id video_device_ids[] = {
|
|
|
{ACPI_VIDEO_HID, 0},
|
|
@@ -89,6 +93,7 @@ static struct acpi_driver acpi_video_bus = {
|
|
|
.ops = {
|
|
|
.add = acpi_video_bus_add,
|
|
|
.remove = acpi_video_bus_remove,
|
|
|
+ .resume = acpi_video_resume,
|
|
|
},
|
|
|
};
|
|
|
|
|
@@ -275,7 +280,6 @@ static void acpi_video_device_rebind(struct acpi_video_bus *video);
|
|
|
static void acpi_video_device_bind(struct acpi_video_bus *video,
|
|
|
struct acpi_video_device *device);
|
|
|
static int acpi_video_device_enumerate(struct acpi_video_bus *video);
|
|
|
-static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
|
|
|
static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
|
|
|
int level);
|
|
|
static int acpi_video_device_lcd_get_level_current(
|
|
@@ -800,11 +804,40 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
|
|
|
static int acpi_video_bus_check(struct acpi_video_bus *video)
|
|
|
{
|
|
|
acpi_status status = -ENOENT;
|
|
|
-
|
|
|
+ long device_id;
|
|
|
+ struct device *dev;
|
|
|
+ struct acpi_device *device;
|
|
|
|
|
|
if (!video)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ device = video->device;
|
|
|
+
|
|
|
+ status =
|
|
|
+ acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
|
|
|
+
|
|
|
+ if (!ACPI_SUCCESS(status))
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ /* We need to attempt to determine whether the _ADR refers to a
|
|
|
+ PCI device or not. There's no terribly good way to do this,
|
|
|
+ so the best we can hope for is to assume that there'll never
|
|
|
+ be a video device in the host bridge */
|
|
|
+ if (device_id >= 0x10000) {
|
|
|
+ /* It looks like a PCI device. Does it exist? */
|
|
|
+ dev = acpi_get_physical_device(device->handle);
|
|
|
+ } else {
|
|
|
+ /* It doesn't look like a PCI device. Does its parent
|
|
|
+ exist? */
|
|
|
+ acpi_handle phandle;
|
|
|
+ if (acpi_get_parent(device->handle, &phandle))
|
|
|
+ return -ENODEV;
|
|
|
+ dev = acpi_get_physical_device(phandle);
|
|
|
+ }
|
|
|
+ if (!dev)
|
|
|
+ return -ENODEV;
|
|
|
+ put_device(dev);
|
|
|
+
|
|
|
/* Since there is no HID, CID and so on for VGA driver, we have
|
|
|
* to check well known required nodes.
|
|
|
*/
|
|
@@ -1683,64 +1716,6 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Arg:
|
|
|
- * video : video bus device
|
|
|
- * event : notify event
|
|
|
- *
|
|
|
- * Return:
|
|
|
- * < 0 : error
|
|
|
- *
|
|
|
- * 1. Find out the current active output device.
|
|
|
- * 2. Identify the next output device to switch to.
|
|
|
- * 3. call _DSS to do actual switch.
|
|
|
- */
|
|
|
-
|
|
|
-static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
|
|
|
-{
|
|
|
- struct list_head *node;
|
|
|
- struct acpi_video_device *dev = NULL;
|
|
|
- struct acpi_video_device *dev_next = NULL;
|
|
|
- struct acpi_video_device *dev_prev = NULL;
|
|
|
- unsigned long state;
|
|
|
- int status = 0;
|
|
|
-
|
|
|
- mutex_lock(&video->device_list_lock);
|
|
|
-
|
|
|
- list_for_each(node, &video->video_device_list) {
|
|
|
- dev = container_of(node, struct acpi_video_device, entry);
|
|
|
- status = acpi_video_device_get_state(dev, &state);
|
|
|
- if (state & 0x2) {
|
|
|
- dev_next = container_of(node->next,
|
|
|
- struct acpi_video_device, entry);
|
|
|
- dev_prev = container_of(node->prev,
|
|
|
- struct acpi_video_device, entry);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- dev_next = container_of(node->next, struct acpi_video_device, entry);
|
|
|
- dev_prev = container_of(node->prev, struct acpi_video_device, entry);
|
|
|
-
|
|
|
- out:
|
|
|
- mutex_unlock(&video->device_list_lock);
|
|
|
-
|
|
|
- switch (event) {
|
|
|
- case ACPI_VIDEO_NOTIFY_CYCLE:
|
|
|
- case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
|
|
|
- acpi_video_device_set_state(dev, 0);
|
|
|
- acpi_video_device_set_state(dev_next, 0x80000001);
|
|
|
- break;
|
|
|
- case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
|
|
|
- acpi_video_device_set_state(dev, 0);
|
|
|
- acpi_video_device_set_state(dev_prev, 0x80000001);
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
static int
|
|
|
acpi_video_get_next_level(struct acpi_video_device *device,
|
|
|
u32 level_current, u32 event)
|
|
@@ -1908,23 +1883,19 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
|
|
|
* connector. */
|
|
|
acpi_video_device_enumerate(video);
|
|
|
acpi_video_device_rebind(video);
|
|
|
- acpi_video_switch_output(video, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_SWITCHVIDEOMODE;
|
|
|
break;
|
|
|
|
|
|
case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */
|
|
|
- acpi_video_switch_output(video, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_SWITCHVIDEOMODE;
|
|
|
break;
|
|
|
case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
|
|
|
- acpi_video_switch_output(video, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_VIDEO_NEXT;
|
|
|
break;
|
|
|
case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
|
|
|
- acpi_video_switch_output(video, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_VIDEO_PREV;
|
|
|
break;
|
|
@@ -1936,6 +1907,7 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ acpi_notifier_call_chain(device, event, 0);
|
|
|
input_report_key(input, keycode, 1);
|
|
|
input_sync(input);
|
|
|
input_report_key(input, keycode, 0);
|
|
@@ -1961,27 +1933,32 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
|
|
|
|
|
|
switch (event) {
|
|
|
case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
|
|
|
- acpi_video_switch_brightness(video_device, event);
|
|
|
+ if (brightness_switch_enabled)
|
|
|
+ acpi_video_switch_brightness(video_device, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_BRIGHTNESS_CYCLE;
|
|
|
break;
|
|
|
case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
|
|
|
- acpi_video_switch_brightness(video_device, event);
|
|
|
+ if (brightness_switch_enabled)
|
|
|
+ acpi_video_switch_brightness(video_device, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_BRIGHTNESSUP;
|
|
|
break;
|
|
|
case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
|
|
|
- acpi_video_switch_brightness(video_device, event);
|
|
|
+ if (brightness_switch_enabled)
|
|
|
+ acpi_video_switch_brightness(video_device, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_BRIGHTNESSDOWN;
|
|
|
break;
|
|
|
case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
|
|
|
- acpi_video_switch_brightness(video_device, event);
|
|
|
+ if (brightness_switch_enabled)
|
|
|
+ acpi_video_switch_brightness(video_device, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_BRIGHTNESS_ZERO;
|
|
|
break;
|
|
|
case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
|
|
|
- acpi_video_switch_brightness(video_device, event);
|
|
|
+ if (brightness_switch_enabled)
|
|
|
+ acpi_video_switch_brightness(video_device, event);
|
|
|
acpi_bus_generate_proc_event(device, event, 0);
|
|
|
keycode = KEY_DISPLAY_OFF;
|
|
|
break;
|
|
@@ -1992,6 +1969,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ acpi_notifier_call_chain(device, event, 0);
|
|
|
input_report_key(input, keycode, 1);
|
|
|
input_sync(input);
|
|
|
input_report_key(input, keycode, 0);
|
|
@@ -2001,6 +1979,25 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
|
|
|
}
|
|
|
|
|
|
static int instance;
|
|
|
+static int acpi_video_resume(struct acpi_device *device)
|
|
|
+{
|
|
|
+ struct acpi_video_bus *video;
|
|
|
+ struct acpi_video_device *video_device;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!device || !acpi_driver_data(device))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ video = acpi_driver_data(device);
|
|
|
+
|
|
|
+ for (i = 0; i < video->attached_count; i++) {
|
|
|
+ video_device = video->attached_array[i].bind_info;
|
|
|
+ if (video_device && video_device->backlight)
|
|
|
+ acpi_video_set_brightness(video_device->backlight);
|
|
|
+ }
|
|
|
+ return AE_OK;
|
|
|
+}
|
|
|
+
|
|
|
static int acpi_video_bus_add(struct acpi_device *device)
|
|
|
{
|
|
|
acpi_status status;
|