diff options
Diffstat (limited to 'drivers/acpi/acpi_video.c')
-rw-r--r-- | drivers/acpi/acpi_video.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 5fdac3942..a76f8be1b 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -77,6 +77,13 @@ module_param(allow_duplicates, bool, 0644); static int disable_backlight_sysfs_if = -1; module_param(disable_backlight_sysfs_if, int, 0444); +#define REPORT_OUTPUT_KEY_EVENTS 0x01 +#define REPORT_BRIGHTNESS_KEY_EVENTS 0x02 +static int report_key_events = -1; +module_param(report_key_events, int, 0644); +MODULE_PARM_DESC(report_key_events, + "0: none, 1: output changes, 2: brightness changes, 3: all"); + static bool device_id_scheme = false; module_param(device_id_scheme, bool, 0444); @@ -85,8 +92,8 @@ module_param(only_lcd, bool, 0444); static int register_count; static DEFINE_MUTEX(register_count_mutex); -static struct mutex video_list_lock; -static struct list_head video_bus_head; +static DEFINE_MUTEX(video_list_lock); +static LIST_HEAD(video_bus_head); static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device); static void acpi_video_bus_notify(struct acpi_device *device, u32 event); @@ -412,6 +419,13 @@ static int video_enable_only_lcd(const struct dmi_system_id *d) return 0; } +static int video_set_report_key_events(const struct dmi_system_id *id) +{ + if (report_key_events == -1) + report_key_events = (uintptr_t)id->driver_data; + return 0; +} + static struct dmi_system_id video_dmi_table[] = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -518,6 +532,24 @@ static struct dmi_system_id video_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"), }, }, + /* + * Some machines report wrong key events on the acpi-bus, suppress + * key event reporting on these. Note this is only intended to work + * around events which are plain wrong. In some cases we get double + * events, in this case acpi-video is considered the canonical source + * and the events from the other source should be filtered. E.g. + * by calling acpi_video_handles_brightness_key_presses() from the + * vendor acpi/wmi driver or by using /lib/udev/hwdb.d/60-keyboard.hwdb + */ + { + .callback = video_set_report_key_events, + .driver_data = (void *)((uintptr_t)REPORT_OUTPUT_KEY_EVENTS), + .ident = "Dell Vostro V131", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), + }, + }, {} }; @@ -1498,7 +1530,7 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) /* Something vetoed the keypress. */ keycode = 0; - if (keycode) { + if (keycode && (report_key_events & REPORT_OUTPUT_KEY_EVENTS)) { input_report_key(input, keycode, 1); input_sync(input); input_report_key(input, keycode, 0); @@ -1562,7 +1594,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) acpi_notifier_call_chain(device, event, 0); - if (keycode) { + if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) { input_report_key(input, keycode, 1); input_sync(input); input_report_key(input, keycode, 0); @@ -2044,9 +2076,6 @@ int acpi_video_register(void) goto leave; } - mutex_init(&video_list_lock); - INIT_LIST_HEAD(&video_bus_head); - dmi_check_system(video_dmi_table); ret = acpi_bus_register_driver(&acpi_video_bus); @@ -2090,6 +2119,19 @@ void acpi_video_unregister_backlight(void) mutex_unlock(®ister_count_mutex); } +bool acpi_video_handles_brightness_key_presses(void) +{ + bool have_video_busses; + + mutex_lock(&video_list_lock); + have_video_busses = !list_empty(&video_bus_head); + mutex_unlock(&video_list_lock); + + return have_video_busses && + (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS); +} +EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses); + /* * This is kind of nasty. Hardware using Intel chipsets may require * the video opregion code to be run first in order to initialise |