summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/tegra/dc/ext/dev.c158
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h20
-rw-r--r--include/video/tegra_dc_ext.h93
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 */