video: tegra: dc: return number of modes in modedb when modedb_len==0
Andy Ritger [Fri, 19 Jul 2013 04:20:32 +0000 (21:20 -0700)]
When servicing the FBIO_TEGRA_GET_MODEDB ioctl, always walk through the
modelist to count the number of modes.  If modedb_len==0, return the
total mode count.  Otherwise, return the number of modes written
into the modedb array.

Bug 1324827

Change-Id: I4ad8f3c3ca3cb0ba7a4ad36c508a75abca964a25
Signed-off-by: Andy Ritger <aritger@nvidia.com>
Reviewed-on: http://git-master/r/251141
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Jon Mayo <jmayo@nvidia.com>

drivers/video/tegra/fb.c

index 0f4b0f4..c4a7f1a 100644 (file)
@@ -410,9 +410,6 @@ static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long
                list_for_each_entry(modelist, &info->modelist, list) {
                        struct fb_var_screeninfo var;
 
-                       if (i >= modedb.modedb_len)
-                               break;
-
                        /* fb_videomode_to_var doesn't fill out all the members
                           of fb_var_screeninfo */
                        memset(&var, 0x0, sizeof(var));
@@ -421,23 +418,33 @@ static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long
                        var.width = tegra_dc_get_out_width(dc);
                        var.height = tegra_dc_get_out_height(dc);
 
-                       if (copy_to_user((void __user *)&modedb.modedb[i],
-                                        &var, sizeof(var)))
-                               return -EFAULT;
+                       if (i < modedb.modedb_len) {
+                               void __user *ptr = &modedb.modedb[i];
+                               if (copy_to_user(ptr, &var, sizeof(var)))
+                                       return -EFAULT;
+                       }
                        i++;
 
                        if (var.vmode & FB_VMODE_STEREO_MASK) {
-                               if (i >= modedb.modedb_len)
-                                       break;
-                               var.vmode &= ~FB_VMODE_STEREO_MASK;
-                               if (copy_to_user(
-                                       (void __user *)&modedb.modedb[i],
-                                        &var, sizeof(var)))
-                                       return -EFAULT;
+                               if (i < modedb.modedb_len) {
+                                       void __user *ptr = &modedb.modedb[i];
+                                       var.vmode &= ~FB_VMODE_STEREO_MASK;
+                                       if (copy_to_user(ptr,
+                                               &var, sizeof(var)))
+                                               return -EFAULT;
+                               }
                                i++;
                        }
                }
-               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);
 
                if (copy_to_user((void __user *)arg, &modedb, sizeof(modedb)))
                        return -EFAULT;