diff options
-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 | ||||
-rw-r--r-- | include/video/tegra_dc_ext.h | 93 |
3 files changed, 265 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 */ diff --git a/include/video/tegra_dc_ext.h b/include/video/tegra_dc_ext.h new file mode 100644 index 000000000000..18f2262a13c1 --- /dev/null +++ b/include/video/tegra_dc_ext.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011, NVIDIA Corporation + * + * Author: Robert Morell <rmorell@nvidia.com> + * Some code based on fbdev extensions written by: + * Erik Gilling <konkers@android.com> + * + * 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. + */ + +#ifndef __TEGRA_DC_EXT_H +#define __TEGRA_DC_EXT_H + +#include <linux/types.h> +#include <linux/ioctl.h> + +#define TEGRA_DC_EXT_FMT_P1 0 +#define TEGRA_DC_EXT_FMT_P2 1 +#define TEGRA_DC_EXT_FMT_P4 2 +#define TEGRA_DC_EXT_FMT_P8 3 +#define TEGRA_DC_EXT_FMT_B4G4R4A4 4 +#define TEGRA_DC_EXT_FMT_B5G5R5A 5 +#define TEGRA_DC_EXT_FMT_B5G6R5 6 +#define TEGRA_DC_EXT_FMT_AB5G5R5 7 +#define TEGRA_DC_EXT_FMT_B8G8R8A8 12 +#define TEGRA_DC_EXT_FMT_R8G8B8A8 13 +#define TEGRA_DC_EXT_FMT_B6x2G6x2R6x2A8 14 +#define TEGRA_DC_EXT_FMT_R6x2G6x2B6x2A8 15 +#define TEGRA_DC_EXT_FMT_YCbCr422 16 +#define TEGRA_DC_EXT_FMT_YUV422 17 +#define TEGRA_DC_EXT_FMT_YCbCr420P 18 +#define TEGRA_DC_EXT_FMT_YUV420P 19 +#define TEGRA_DC_EXT_FMT_YCbCr422P 20 +#define TEGRA_DC_EXT_FMT_YUV422P 21 +#define TEGRA_DC_EXT_FMT_YCbCr422R 22 +#define TEGRA_DC_EXT_FMT_YUV422R 23 +#define TEGRA_DC_EXT_FMT_YCbCr422RA 24 +#define TEGRA_DC_EXT_FMT_YUV422RA 25 + +#define TEGRA_DC_EXT_BLEND_NONE 0 +#define TEGRA_DC_EXT_BLEND_PREMULT 1 +#define TEGRA_DC_EXT_BLEND_COVERAGE 2 + +struct tegra_dc_ext_flip_windowattr { + __s32 index; + __u32 buff_id; + __u32 blend; + __u32 offset; + __u32 offset_u; + __u32 offset_v; + __u32 stride; + __u32 stride_uv; + __u32 pixformat; + __u32 x; + __u32 y; + __u32 w; + __u32 h; + __u32 out_x; + __u32 out_y; + __u32 out_w; + __u32 out_h; + __u32 z; + __u32 pre_syncpt_id; + __u32 pre_syncpt_val; +}; + +#define TEGRA_DC_EXT_FLIP_N_WINDOWS 3 + +struct tegra_dc_ext_flip { + struct tegra_dc_ext_flip_windowattr win[TEGRA_DC_EXT_FLIP_N_WINDOWS]; +}; + +#define TEGRA_DC_EXT_SET_NVMAP_FD \ + _IOW('D', 0x00, __s32) + +#define TEGRA_DC_EXT_GET_WINDOW \ + _IOW('D', 0x01, __u32) +#define TEGRA_DC_EXT_PUT_WINDOW \ + _IOW('D', 0x02, __u32) + +#define TEGRA_DC_EXT_FLIP \ + _IOWR('D', 0x03, struct tegra_dc_ext_flip) + + +#endif /* __TEGRA_DC_EXT_H */ |