From d827065381dbcd0d4884267b86397fb2af009c21 Mon Sep 17 00:00:00 2001 From: Jon McCaffrey Date: Mon, 22 Aug 2011 14:49:04 -0700 Subject: 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 Tested-by: Rohan Somvanshi --- drivers/video/tegra/dc/Makefile | 1 + drivers/video/tegra/dc/dc_input.c | 117 ++++++++++++++++++++++++++++++++++++++ drivers/video/tegra/dc/dc_input.h | 35 ++++++++++++ drivers/video/tegra/dc/overlay.c | 21 ++++++- 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 drivers/video/tegra/dc/dc_input.c create mode 100644 drivers/video/tegra/dc/dc_input.h 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 +#include +#include + +#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); -- cgit v1.2.3