report acpi video hot key event through input device Signed-off-by: Luming Yu <Luming.yu@xxxxxxxxx> -- diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 00d25b3..03d84db 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -31,6 +31,7 @@ #include <linux/list.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/input.h> #include <linux/backlight.h> #include <asm/uaccess.h> @@ -131,6 +132,8 @@ struct acpi_video_bus { struct semaphore sem; struct list_head video_device_list; struct proc_dir_entry *dir; + struct input_dev *input; + char phys[32]; /* for input device */ }; struct acpi_video_device_flags { @@ -1714,6 +1717,8 @@ static void acpi_video_bus_notify(acpi_h { struct acpi_video_bus *video = data; struct acpi_device *device = NULL; + struct input_dev *input; + int keycode; printk("video bus notify\n"); @@ -1721,11 +1726,13 @@ static void acpi_video_bus_notify(acpi_h return; device = video->device; + input = video->input; switch (event) { case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, * most likely via hotkey. */ acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; break; case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video @@ -1734,21 +1741,37 @@ static void acpi_video_bus_notify(acpi_h acpi_video_device_rebind(video); acpi_video_switch_output(video, event); acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; break; case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ + acpi_video_switch_output(video, event); + acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; + break; case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ + acpi_video_switch_output(video, event); + acpi_bus_generate_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_event(device, event, 0); + keycode = KEY_VIDEO_PREV; break; default: + keycode = KEY_UNKNOWN; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + return; } @@ -1756,30 +1779,60 @@ static void acpi_video_device_notify(acp { struct acpi_video_device *video_device = data; struct acpi_device *device = NULL; + struct acpi_video_bus *bus; + struct input_dev *input; + int keycode; if (!video_device) return; device = video_device->dev; + bus = video_device->video; + input = bus->input; switch (event) { case ACPI_VIDEO_NOTIFY_SWITCH: /* change in status (cycle output device) */ case ACPI_VIDEO_NOTIFY_PROBE: /* change in status (output device status) */ acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; break; case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ + acpi_video_switch_brightness(video_device, event); + acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; + break; case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ + acpi_video_switch_brightness(video_device, event); + acpi_bus_generate_event(device, event, 0); + keycode = KEY_BRIGHTNESS_UP; + break; case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ + acpi_video_switch_brightness(video_device, event); + acpi_bus_generate_event(device, event, 0); + keycode = KEY_BRIGHTNESS_DOWN; + break; case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */ + acpi_video_switch_brightness(video_device, event); + acpi_bus_generate_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); acpi_bus_generate_event(device, event, 0); + keycode = KEY_BRIGHTNESS_OFF; break; default: + keycode = KEY_UNKNOWN; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } + + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + return; } @@ -1788,7 +1841,7 @@ static int acpi_video_bus_add(struct acp int result = 0; acpi_status status = 0; struct acpi_video_bus *video = NULL; - + struct input_dev *input; if (!device) return -EINVAL; @@ -1830,7 +1883,18 @@ static int acpi_video_bus_add(struct acp result = -ENODEV; goto end; } - + + video->input = input = input_allocate_device(); + + snprintf(video->phys, sizeof(video->phys), + "%s/video/input0", acpi_device_bid(video->device)); + + input->name = acpi_device_name(video->device); + input->phys = video->phys; + input->id.bustype = BUS_HOST; + input->id.product = 0x06; + input->evbit[0] = BIT(EV_KEY); + input_register_device(input); printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n", ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), video->flags.multihead ? "yes" : "no", @@ -1863,7 +1927,7 @@ static int acpi_video_bus_remove(struct acpi_video_bus_put_devices(video); acpi_video_bus_remove_fs(device); - + input_unregister_device(video->input); kfree(video->attached_array); kfree(video); diff --git a/include/linux/input.h b/include/linux/input.h index be2bf3a..2ccdb50 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -544,6 +544,13 @@ struct input_absinfo { #define KEY_BRL_DOT7 0x1f7 #define KEY_BRL_DOT8 0x1f8 +#define KEY_VIDEO_NEXT 0x1f9 +#define KEY_VIDEO_PREV 0x1fa +#define KEY_BRIGHTNESS_UP 0x1fb +#define KEY_BRIGHTNESS_DOWN 0x1fc +#define KEY_BRIGHTNESS_ZERO 0x1fd +#define KEY_BRIGHTNESS_OFF 0x1fe + /* We avoid low common keys in module aliases so they don't get huge. */ #define KEY_MIN_INTERESTING KEY_MUTE #define KEY_MAX 0x1ff
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 00d25b3..03d84db 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -31,6 +31,7 @@ #include <linux/list.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/input.h> #include <linux/backlight.h> #include <asm/uaccess.h> @@ -131,6 +132,8 @@ struct acpi_video_bus { struct semaphore sem; struct list_head video_device_list; struct proc_dir_entry *dir; + struct input_dev *input; + char phys[32]; /* for input device */ }; struct acpi_video_device_flags { @@ -1714,6 +1717,8 @@ static void acpi_video_bus_notify(acpi_h { struct acpi_video_bus *video = data; struct acpi_device *device = NULL; + struct input_dev *input; + int keycode; printk("video bus notify\n"); @@ -1721,11 +1726,13 @@ static void acpi_video_bus_notify(acpi_h return; device = video->device; + input = video->input; switch (event) { case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, * most likely via hotkey. */ acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; break; case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video @@ -1734,21 +1741,37 @@ static void acpi_video_bus_notify(acpi_h acpi_video_device_rebind(video); acpi_video_switch_output(video, event); acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; break; case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ + acpi_video_switch_output(video, event); + acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; + break; case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ + acpi_video_switch_output(video, event); + acpi_bus_generate_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_event(device, event, 0); + keycode = KEY_VIDEO_PREV; break; default: + keycode = KEY_UNKNOWN; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + return; } @@ -1756,30 +1779,60 @@ static void acpi_video_device_notify(acp { struct acpi_video_device *video_device = data; struct acpi_device *device = NULL; + struct acpi_video_bus *bus; + struct input_dev *input; + int keycode; if (!video_device) return; device = video_device->dev; + bus = video_device->video; + input = bus->input; switch (event) { case ACPI_VIDEO_NOTIFY_SWITCH: /* change in status (cycle output device) */ case ACPI_VIDEO_NOTIFY_PROBE: /* change in status (output device status) */ acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; break; case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ + acpi_video_switch_brightness(video_device, event); + acpi_bus_generate_event(device, event, 0); + keycode = KEY_UNKNOWN; + break; case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ + acpi_video_switch_brightness(video_device, event); + acpi_bus_generate_event(device, event, 0); + keycode = KEY_BRIGHTNESS_UP; + break; case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ + acpi_video_switch_brightness(video_device, event); + acpi_bus_generate_event(device, event, 0); + keycode = KEY_BRIGHTNESS_DOWN; + break; case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */ + acpi_video_switch_brightness(video_device, event); + acpi_bus_generate_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); acpi_bus_generate_event(device, event, 0); + keycode = KEY_BRIGHTNESS_OFF; break; default: + keycode = KEY_UNKNOWN; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } + + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + return; } @@ -1788,7 +1841,7 @@ static int acpi_video_bus_add(struct acp int result = 0; acpi_status status = 0; struct acpi_video_bus *video = NULL; - + struct input_dev *input; if (!device) return -EINVAL; @@ -1830,7 +1883,18 @@ static int acpi_video_bus_add(struct acp result = -ENODEV; goto end; } - + + video->input = input = input_allocate_device(); + + snprintf(video->phys, sizeof(video->phys), + "%s/video/input0", acpi_device_bid(video->device)); + + input->name = acpi_device_name(video->device); + input->phys = video->phys; + input->id.bustype = BUS_HOST; + input->id.product = 0x06; + input->evbit[0] = BIT(EV_KEY); + input_register_device(input); printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n", ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), video->flags.multihead ? "yes" : "no", @@ -1863,7 +1927,7 @@ static int acpi_video_bus_remove(struct acpi_video_bus_put_devices(video); acpi_video_bus_remove_fs(device); - + input_unregister_device(video->input); kfree(video->attached_array); kfree(video); diff --git a/include/linux/input.h b/include/linux/input.h index be2bf3a..2ccdb50 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -544,6 +544,13 @@ struct input_absinfo { #define KEY_BRL_DOT7 0x1f7 #define KEY_BRL_DOT8 0x1f8 +#define KEY_VIDEO_NEXT 0x1f9 +#define KEY_VIDEO_PREV 0x1fa +#define KEY_BRIGHTNESS_UP 0x1fb +#define KEY_BRIGHTNESS_DOWN 0x1fc +#define KEY_BRIGHTNESS_ZERO 0x1fd +#define KEY_BRIGHTNESS_OFF 0x1fe + /* We avoid low common keys in module aliases so they don't get huge. */ #define KEY_MIN_INTERESTING KEY_MUTE #define KEY_MAX 0x1ff