video: tegra: Add an ioctl() implementation.
Robert Morell [Wed, 16 Feb 2011 02:13:36 +0000 (18:13 -0800)]
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

drivers/video/tegra/dc/ext/dev.c
drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
include/video/tegra_dc_ext.h [new file with mode: 0644]

index bb5c99e..a0c9592 100644 (file)
 
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/export.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;
 }
 
@@ -97,10 +238,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);
 
index 387af54..27dfbcb 100644 (file)
 #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 (file)
index 0000000..18f2262
--- /dev/null
@@ -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 */