diff options
author | Robert Morell <rmorell@nvidia.com> | 2011-02-15 18:13:36 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:48:11 -0800 |
commit | ead8aaa0c6be72c6028cc1a75ba70baaf31ff2d9 (patch) | |
tree | c95c93987feabb122087d417ecf4b43bd1229e4d /drivers/video/tegra/dc/ext | |
parent | 4d785e53437e27a0bbf57f26c66dcad3bacd35f0 (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.c | 158 | ||||
-rw-r--r-- | drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h | 20 |
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 */ |