summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/tegra/fb.c122
-rw-r--r--include/video/tegrafb.h14
2 files changed, 91 insertions, 45 deletions
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index 36e79dd18203..7ad8711ef7ac 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -404,61 +404,99 @@ static void tegra_fb_imageblit(struct fb_info *info,
cfb_imageblit(info, image);
}
-static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+static int tegra_get_modedb(struct tegra_dc *dc, struct tegra_fb_modedb *modedb,
+ struct fb_info *info)
{
- struct tegra_fb_info *tegra_fb = (struct tegra_fb_info *)info->par;
- struct tegra_dc *dc = tegra_fb->win->dc;
- struct tegra_fb_modedb modedb;
- struct fb_modelist *modelist;
- struct fb_vblank vblank = {};
- struct fb_var_screeninfo *modedb_ptr;
unsigned i;
+ struct fb_var_screeninfo *modedb_ptr;
+ struct fb_modelist *modelist;
- switch (cmd) {
- case FBIO_TEGRA_GET_MODEDB:
- if (copy_from_user(&modedb, (void __user *)arg, sizeof(modedb)))
- return -EFAULT;
+ i = 0;
+ modedb_ptr = user_ptr(modedb->modedb);
+ list_for_each_entry(modelist, &info->modelist, list) {
+ struct fb_var_screeninfo var;
+
+ /* fb_videomode_to_var doesn't fill out all the members
+ of fb_var_screeninfo */
+ memset(&var, 0x0, sizeof(var));
- i = 0;
- modedb_ptr = user_ptr(modedb.modedb);
- list_for_each_entry(modelist, &info->modelist, list) {
- struct fb_var_screeninfo var;
+ fb_videomode_to_var(&var, &modelist->mode);
+ var.width = tegra_dc_get_out_width(dc);
+ var.height = tegra_dc_get_out_height(dc);
- /* fb_videomode_to_var doesn't fill out all the members
- of fb_var_screeninfo */
- memset(&var, 0x0, sizeof(var));
+ if (i < modedb->modedb_len) {
+ void __user *ptr = &modedb_ptr[i];
- fb_videomode_to_var(&var, &modelist->mode);
- var.width = tegra_dc_get_out_width(dc);
- var.height = tegra_dc_get_out_height(dc);
+ if (copy_to_user(ptr, &var, sizeof(var)))
+ return -EFAULT;
+ }
+ i++;
- if (i < modedb.modedb_len) {
+ if (var.vmode & FB_VMODE_STEREO_MASK) {
+ if (i < modedb->modedb_len) {
void __user *ptr = &modedb_ptr[i];
- if (copy_to_user(ptr, &var, sizeof(var)))
+
+ var.vmode &= ~FB_VMODE_STEREO_MASK;
+ if (copy_to_user(ptr,
+ &var, sizeof(var)))
return -EFAULT;
}
i++;
-
- if (var.vmode & FB_VMODE_STEREO_MASK) {
- if (i < modedb.modedb_len) {
- void __user *ptr = &modedb_ptr[i];
- var.vmode &= ~FB_VMODE_STEREO_MASK;
- if (copy_to_user(ptr,
- &var, sizeof(var)))
- return -EFAULT;
- }
- i++;
- }
}
+ }
- /*
- * If modedb_len == 0, return how many modes are
- * available; otherwise, return how many modes were written.
- */
- if (modedb.modedb_len == 0)
- modedb.modedb_len = i;
- else
- modedb.modedb_len = min(modedb.modedb_len, i);
+ /*
+ * If modedb_len == 0, return how many modes are
+ * available; otherwise, return how many modes were written.
+ */
+ if (modedb->modedb_len == 0)
+ modedb->modedb_len = i;
+ else
+ modedb->modedb_len = min(modedb->modedb_len, i);
+
+ return 0;
+}
+
+static int tegra_fb_ioctl(struct fb_info *info,
+ unsigned int cmd, unsigned long arg)
+{
+ int res;
+ struct tegra_fb_info *tegra_fb = (struct tegra_fb_info *)info->par;
+ struct tegra_dc *dc = tegra_fb->win->dc;
+ struct tegra_fb_modedb modedb;
+ struct fb_vblank vblank = {};
+
+ switch (cmd) {
+#ifdef CONFIG_COMPAT
+ case FBIO_TEGRA_GET_MODEDB_COMPAT: {
+ struct tegra_fb_modedb_compat modedb_compat;
+
+ if (copy_from_user(&modedb_compat, (void __user *)arg,
+ sizeof(modedb_compat)))
+ return -EFAULT;
+ /* convert compat version to full version */
+ modedb.modedb = (void __user *)modedb_compat.modedb;
+ modedb.modedb_len = modedb_compat.modedb_len;
+
+ res = tegra_get_modedb(dc, &modedb, info);
+ if (res)
+ return res;
+
+ /* convert full version back to compat version */
+ modedb_compat.modedb_len = modedb.modedb_len;
+ if (copy_to_user((void __user *)arg, &modedb_compat,
+ sizeof(modedb_compat)))
+ return -EFAULT;
+ break;
+ }
+#endif
+ case FBIO_TEGRA_GET_MODEDB:
+ if (copy_from_user(&modedb, (void __user *)arg, sizeof(modedb)))
+ return -EFAULT;
+
+ res = tegra_get_modedb(dc, &modedb, info);
+ if (res)
+ return res;
if (copy_to_user((void __user *)arg, &modedb, sizeof(modedb)))
return -EFAULT;
diff --git a/include/video/tegrafb.h b/include/video/tegrafb.h
index 60bf30944af3..c524c083a3c5 100644
--- a/include/video/tegrafb.h
+++ b/include/video/tegrafb.h
@@ -4,6 +4,8 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
+ * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved.
+ *
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
@@ -26,14 +28,20 @@
#endif
struct tegra_fb_modedb {
+ struct fb_var_screeninfo *modedb;
+ __u32 modedb_len;
+};
+
#ifdef CONFIG_COMPAT
+struct tegra_fb_modedb_compat {
__u32 modedb;
-#else
- struct fb_var_screeninfo *modedb;
-#endif
__u32 modedb_len;
};
+#define FBIO_TEGRA_GET_MODEDB_COMPAT \
+ _IOWR('F', 0x42, struct tegra_fb_modedb_compat)
+#endif
+
#define FBIO_TEGRA_GET_MODEDB _IOWR('F', 0x42, struct tegra_fb_modedb)
#endif