diff options
author | Jon McCaffrey <jmccaffrey@nvidia.com> | 2011-08-22 14:49:04 -0700 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2011-09-06 03:03:43 -0700 |
commit | d827065381dbcd0d4884267b86397fb2af009c21 (patch) | |
tree | 9069ea88d5aa6bf6761a95d52b7c84f3e993b49a /drivers/video | |
parent | 3a85d02f0d61f8d94b864716ce7f3f12e78d62a0 (diff) |
video: tegra: dc: fake input device
Bug 855811
For smoothness and rate-limiting, it is useful to synchronize input
events to flip. This patch adds a fake input device that emits an event
on each vsync. This allows the Android input framework, which has
significant infrastructure to monitor input devices in particular, to be
notified of vsync events.
Because there is no input event type/code for this behavior, we use an
undocumented protocol of emitting a single MSC_RAW type event with
scan-code 1. We also do not register ourselves for any other
buttons/keys, which should prevent our device node from being confused
with other input types.
Change-Id: Id5297d2cef93eb53737942b43b2b09b82dee5f6f
Reviewed-on: http://git-master/r/48539
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/tegra/dc/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_input.c | 117 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_input.h | 35 | ||||
-rw-r--r-- | drivers/video/tegra/dc/overlay.c | 21 |
4 files changed, 173 insertions, 1 deletions
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile index 90b03892673c..73595be8a46a 100644 --- a/drivers/video/tegra/dc/Makefile +++ b/drivers/video/tegra/dc/Makefile @@ -1,4 +1,5 @@ obj-y += dc.o +obj-y += dc_input.o obj-y += rgb.o obj-y += hdmi.o obj-y += nvhdcp.o diff --git a/drivers/video/tegra/dc/dc_input.c b/drivers/video/tegra/dc/dc_input.c new file mode 100644 index 000000000000..a4b37a9313ca --- /dev/null +++ b/drivers/video/tegra/dc/dc_input.c @@ -0,0 +1,117 @@ +/* + * drivers/video/tegra/overlay/dc_input.c + * + * Copyright (c) 2010-2011, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/input.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> + +#include "dc_input.h" + +struct dc_input { + struct input_dev *dev; + char name[40]; + atomic_t listeners; +}; + +static int dc_input_open(struct input_dev *dev) +{ + struct dc_input *data = input_get_drvdata(dev); + if (data) + atomic_inc(&data->listeners); + return 0; +} + +static void dc_input_close(struct input_dev *dev) +{ + struct dc_input *data = input_get_drvdata(dev); + if (data) + atomic_dec(&data->listeners); +} + +struct dc_input *dc_input_alloc() +{ + return kzalloc(sizeof(struct dc_input), GFP_KERNEL); +} + +int dc_input_init(struct miscdevice *par_dev, + struct dc_input *data) +{ + if (!data) + return -EINVAL; + atomic_set(&data->listeners, 0); + data->dev = input_allocate_device(); + if (!data->dev) + return -ENOMEM; + + snprintf(data->name, sizeof(data->name), + "%s.input_tick", par_dev->name); + + + data->dev->name = data->name; + /* TODO need to set bus type or parent?*/ + + data->dev->open = dc_input_open; + data->dev->close = dc_input_close; + + __set_bit(EV_SYN, data->dev->evbit); + __set_bit(EV_MSC, data->dev->evbit); + __set_bit(MSC_RAW, data->dev->mscbit); + + input_set_drvdata(data->dev, data); + if (input_register_device(data->dev)) + goto err_reg_failed; + + return 0; + +err_reg_failed: + input_free_device(data->dev); + data->dev = NULL; + return -ENOMEM; +} + +void dc_input_destroy(struct dc_input *data) +{ + if (!data || !data->dev) + return; + input_unregister_device(data->dev); + input_free_device(data->dev); + data->dev = NULL; +} + +void dc_input_free(struct dc_input *data) +{ + if (!data) + return; + kfree(data); +} + +int notify_overlay_flip(struct dc_input *data) +{ + int listeners; + if (!data) + return -EINVAL; + listeners = atomic_read(&data->listeners); + /* if noone is listening, don't send */ + if (listeners) { + input_event(data->dev, EV_MSC, MSC_RAW, 1); + input_sync(data->dev); + } + return 0; +} diff --git a/drivers/video/tegra/dc/dc_input.h b/drivers/video/tegra/dc/dc_input.h new file mode 100644 index 000000000000..5c55c78b860a --- /dev/null +++ b/drivers/video/tegra/dc/dc_input.h @@ -0,0 +1,35 @@ +/* + * drivers/video/tegra/overlay/dc_input.h + * + * Copyright (c) 2010-2011, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DC_INPUT_H +#define DC_INPUT_H + +struct dc_input; +struct miscdevice; + +struct dc_input *dc_input_alloc(); +int dc_input_init(struct miscdevice *par_dev, struct dc_input *data); + +int notify_overlay_flip(struct dc_input *data); + +void dc_input_destroy(struct dc_input *data); +void dc_input_free(struct dc_input *data); + +#endif /*DC_INPUT_H*/ diff --git a/drivers/video/tegra/dc/overlay.c b/drivers/video/tegra/dc/overlay.c index 1f31631ea699..e809f76b7fe0 100644 --- a/drivers/video/tegra/dc/overlay.c +++ b/drivers/video/tegra/dc/overlay.c @@ -39,6 +39,8 @@ #include "../nvmap/nvmap.h" #include "overlay.h" +#include "dc_input.h" + /* Minimum extra shot for DIDIM if n shot is enabled. */ #define TEGRA_DC_DIDIM_MIN_SHOT 1 @@ -73,6 +75,8 @@ struct tegra_overlay_info { struct workqueue_struct *flip_wq; struct completion complete; + struct dc_input *input; + /* Big enough for tegra_dc%u when %u < 10 */ char name[10]; }; @@ -674,6 +678,7 @@ static int tegra_overlay_ioctl_flip(struct overlay_client *client, mutex_unlock(&client->dev->dc->lock); return -EPIPE; } + mutex_unlock(&client->dev->dc->lock); if (copy_from_user(&flip_args, arg, sizeof(flip_args))) @@ -716,6 +721,8 @@ static int tegra_overlay_ioctl_flip(struct overlay_client *client, if (copy_to_user(arg, &flip_args, sizeof(flip_args))) return -EFAULT; + notify_overlay_flip(client->dev->input); + return 0; } @@ -902,8 +909,18 @@ struct tegra_overlay_info *tegra_overlay_register(struct nvhost_device *ndev, dev_info(&ndev->dev, "registered overlay\n"); - return dev; + dev->input = dc_input_alloc(); + if (!dev->input) + goto err_delete_wq; + e = dc_input_init(&dev->dev, dev->input); + if (e) + goto err_delete_input; + return dev; +err_delete_input: + dc_input_destroy(dev->input); + dc_input_free(dev->input); + dev->input = NULL; err_delete_wq: err_free: fail: @@ -915,6 +932,8 @@ fail: void tegra_overlay_unregister(struct tegra_overlay_info *info) { + dc_input_destroy(info->input); + dc_input_free(info->input); misc_deregister(&info->dev); kfree(info); |