drm/modes: parse_cmdline: Add freestanding argument to drm_mode_parse_cmdline_options()
[linux-2.6-microblaze.git] / drivers / gpu / drm / drm_modes.c
index 8823269..80cb247 100644 (file)
@@ -1568,33 +1568,49 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
        return 0;
 }
 
-static int drm_mode_parse_cmdline_options(char *str, size_t len,
+static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
+{
+       const char *value;
+       char *endp;
+
+       /*
+        * delim must point to the '=', otherwise it is a syntax error and
+        * if delim points to the terminating zero, then delim + 1 wil point
+        * past the end of the string.
+        */
+       if (*delim != '=')
+               return -EINVAL;
+
+       value = delim + 1;
+       *int_ret = simple_strtol(value, &endp, 10);
+
+       /* Make sure we have parsed something */
+       if (endp == value)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int drm_mode_parse_cmdline_options(const char *str,
+                                         bool freestanding,
                                          const struct drm_connector *connector,
                                          struct drm_cmdline_mode *mode)
 {
-       unsigned int rotation = 0;
-       char *sep = str;
+       unsigned int deg, margin, rotation = 0;
+       const char *delim, *option, *sep;
 
-       while ((sep = strchr(sep, ','))) {
-               char *delim, *option;
-
-               option = sep + 1;
+       option = str;
+       do {
                delim = strchr(option, '=');
                if (!delim) {
                        delim = strchr(option, ',');
 
                        if (!delim)
-                               delim = str + len;
+                               delim = option + strlen(option);
                }
 
                if (!strncmp(option, "rotate", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int deg;
-
-                       deg = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &deg))
                                return -EINVAL;
 
                        switch (deg) {
@@ -1619,58 +1635,37 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
                        }
                } else if (!strncmp(option, "reflect_x", delim - option)) {
                        rotation |= DRM_MODE_REFLECT_X;
-                       sep = delim;
                } else if (!strncmp(option, "reflect_y", delim - option)) {
                        rotation |= DRM_MODE_REFLECT_Y;
-                       sep = delim;
                } else if (!strncmp(option, "margin_right", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int margin;
-
-                       margin = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &margin))
                                return -EINVAL;
 
                        mode->tv_margins.right = margin;
                } else if (!strncmp(option, "margin_left", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int margin;
-
-                       margin = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &margin))
                                return -EINVAL;
 
                        mode->tv_margins.left = margin;
                } else if (!strncmp(option, "margin_top", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int margin;
-
-                       margin = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &margin))
                                return -EINVAL;
 
                        mode->tv_margins.top = margin;
                } else if (!strncmp(option, "margin_bottom", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int margin;
-
-                       margin = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &margin))
                                return -EINVAL;
 
                        mode->tv_margins.bottom = margin;
                } else {
                        return -EINVAL;
                }
-       }
+               sep = strchr(delim, ',');
+               option = sep + 1;
+       } while (sep);
+
+       if (rotation && freestanding)
+               return -EINVAL;
 
        mode->rotation_reflection = rotation;
 
@@ -1726,10 +1721,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
        bool named_mode = false, parse_extras = false;
        unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
        unsigned int mode_end = 0;
-       char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
-       char *options_ptr = NULL;
+       const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+       const char *options_ptr = NULL;
        char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
-       int ret;
+       int i, len, ret;
 
 #ifdef CONFIG_FB
        if (!mode_option)
@@ -1802,6 +1797,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
                mode_end = refresh_off;
        } else if (options_ptr) {
                mode_end = options_off;
+               parse_extras = true;
        } else {
                mode_end = strlen(name);
                parse_extras = true;
@@ -1849,9 +1845,11 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
        else if (refresh_ptr)
                extra_ptr = refresh_end_ptr;
 
-       if (extra_ptr &&
-           extra_ptr != options_ptr) {
-               int len = strlen(name) - (extra_ptr - name);
+       if (extra_ptr) {
+               if (options_ptr)
+                       len = options_ptr - extra_ptr;
+               else
+                       len = strlen(extra_ptr);
 
                ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false,
                                                   connector, mode);
@@ -1860,9 +1858,8 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
        }
 
        if (options_ptr) {
-               int len = strlen(name) - (options_ptr - name);
-
-               ret = drm_mode_parse_cmdline_options(options_ptr, len,
+               ret = drm_mode_parse_cmdline_options(options_ptr + 1,
+                                                    false,
                                                     connector, mode);
                if (ret)
                        return false;