summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/ext
diff options
context:
space:
mode:
authorRobert Morell <rmorell@nvidia.com>2011-02-15 18:13:36 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:11 -0800
commitead8aaa0c6be72c6028cc1a75ba70baaf31ff2d9 (patch)
treec95c93987feabb122087d417ecf4b43bd1229e4d /drivers/video/tegra/dc/ext
parent4d785e53437e27a0bbf57f26c66dcad3bacd35f0 (diff)
video: tegra: Add an ioctl() implementation.
This implements: - GET_WINDOW - PUT_WINDOW and adds a stub for FLIP. bug 818525 Original-Change-Id: I467b58a77242b2a8077e236106b542b8545f5353 Signed-off-by: Robert Morell <rmorell@nvidia.com> Reviewed-on: http://git-master/r/40513 Reviewed-by: Jonathan Mayo <jmayo@nvidia.com> Rebase-Id: R4fc354fdae76f3eac189d481fb346a0982146db5
Diffstat (limited to 'drivers/video/tegra/dc/ext')
-rw-r--r--drivers/video/tegra/dc/ext/dev.c158
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h20
2 files changed, 172 insertions, 6 deletions
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 6fe778896241..e5f8299c1366 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -20,41 +20,182 @@
#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/uaccess.h>
#include <linux/slab.h>
+#include <video/tegra_dc_ext.h>
+
#include <mach/dc.h>
+#include <mach/nvmap.h>
#include <mach/tegra_dc_ext.h>
+/* XXX ew */
+#include "../dc_priv.h"
#include "tegra_dc_ext_priv.h"
static int tegra_dc_ext_devno;
static struct class *tegra_dc_ext_class;
-static int tegra_dc_release(struct inode *inode, struct file *filp)
+static int tegra_dc_ext_set_nvmap_fd(struct tegra_dc_ext_user *user,
+ int fd)
{
- struct tegra_dc_ext_user *user = filp->private_data;
+ struct nvmap_client *nvmap = NULL;
- kfree(user);
+ if (fd < 0)
+ return -EINVAL;
+
+ nvmap = nvmap_client_get_file(fd);
+ if (IS_ERR(nvmap))
+ return PTR_ERR(nvmap);
+
+ if (user->nvmap)
+ nvmap_client_put(user->nvmap);
+
+ user->nvmap = nvmap;
+
+ return 0;
+}
+
+static int tegra_dc_ext_get_window(struct tegra_dc_ext_user *user,
+ unsigned int n)
+{
+ struct tegra_dc_ext *ext = user->ext;
+ struct tegra_dc_ext_win *win;
+ int ret = 0;
+
+ if (n >= DC_N_WINDOWS)
+ return -EINVAL;
+
+ win = &ext->win[n];
+
+ mutex_lock(&win->lock);
+
+ if (!win->user)
+ win->user = user;
+ else if (win->user != user)
+ ret = -EBUSY;
+
+ mutex_unlock(&win->lock);
+
+ return ret;
+}
+
+static int tegra_dc_ext_put_window(struct tegra_dc_ext_user *user,
+ unsigned int n)
+{
+ struct tegra_dc_ext *ext = user->ext;
+ struct tegra_dc_ext_win *win;
+ int ret = 0;
+
+ if (n >= DC_N_WINDOWS)
+ return -EINVAL;
+
+ win = &ext->win[n];
+
+ mutex_lock(&win->lock);
+
+ if (win->user == user)
+ win->user = 0;
+ else
+ ret = -EACCES;
+
+ mutex_unlock(&win->lock);
+ return ret;
+}
+
+static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
+ struct tegra_dc_ext_flip *args)
+{
+ if (!user->nvmap)
+ return -EINVAL;
+
+ printk(KERN_ERR "flip\n");
return 0;
}
+static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *user_arg = (void __user *)arg;
+ struct tegra_dc_ext_user *user = filp->private_data;
+
+ switch (cmd) {
+ case TEGRA_DC_EXT_SET_NVMAP_FD:
+ return tegra_dc_ext_set_nvmap_fd(user, arg);
+
+ case TEGRA_DC_EXT_GET_WINDOW:
+ return tegra_dc_ext_get_window(user, arg);
+ case TEGRA_DC_EXT_PUT_WINDOW:
+ return tegra_dc_ext_put_window(user, arg);
+
+ case TEGRA_DC_EXT_FLIP:
+ {
+ struct tegra_dc_ext_flip args;
+ int ret;
+
+ if (copy_from_user(&args, user_arg, sizeof(args)))
+ return -EFAULT;
+
+ ret = tegra_dc_ext_flip(user, &args);
+
+ if (copy_to_user(user_arg, &args, sizeof(args)))
+ return -EFAULT;
+
+ return ret;
+ }
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int tegra_dc_open(struct inode *inode, struct file *filp)
{
struct tegra_dc_ext_user *user;
+ struct tegra_dc_ext *ext;
user = kzalloc(sizeof(*user), GFP_KERNEL);
if (!user)
return -ENOMEM;
+ ext = container_of(inode->i_cdev, struct tegra_dc_ext, cdev);
+ user->ext = ext;
+
filp->private_data = user;
return 0;
}
-static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int tegra_dc_release(struct inode *inode, struct file *filp)
{
+ struct tegra_dc_ext_user *user = filp->private_data;
+ struct tegra_dc_ext *ext = user->ext;
+ unsigned int i;
+
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ if (ext->win[i].user == user)
+ tegra_dc_ext_put_window(user, i);
+ }
+
+ kfree(user);
+
+ return 0;
+}
+
+static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext)
+{
+ int i;
+
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_ext_win *win = &ext->win[i];
+
+ win->ext = ext;
+ win->idx = i;
+
+ mutex_init(&win->lock);
+ }
+
return 0;
}
@@ -96,10 +237,17 @@ struct tegra_dc_ext *tegra_dc_ext_register(struct nvhost_device *ndev,
goto cleanup_cdev;
}
+ ret = tegra_dc_ext_setup_windows(ext);
+ if (ret)
+ goto cleanup_device;
+
tegra_dc_ext_devno++;
return ext;
+cleanup_device:
+ device_del(ext->dev);
+
cleanup_cdev:
cdev_del(&ext->cdev);
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
index 387af543c511..27dfbcbffb3a 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -20,14 +20,32 @@
#define __TEGRA_DC_EXT_PRIV_H
#include <linux/cdev.h>
+#include <linux/mutex.h>
+
+#include <mach/nvmap.h>
+
+struct tegra_dc_ext_user;
+
+struct tegra_dc_ext_win {
+ struct tegra_dc_ext *ext;
+
+ int idx;
+
+ struct tegra_dc_ext_user *user;
+
+ struct mutex lock;
+};
struct tegra_dc_ext {
struct cdev cdev;
struct device *dev;
+
+ struct tegra_dc_ext_win win[DC_N_WINDOWS];
};
struct tegra_dc_ext_user {
-
+ struct tegra_dc_ext *ext;
+ struct nvmap_client *nvmap;
};
#endif /* __TEGRA_DC_EXT_PRIV_H */