diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch b/target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch new file mode 100644 index 0000000000..24c25d6944 --- /dev/null +++ b/target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch @@ -0,0 +1,392 @@ +From 3508a8548f13be68b6d098ad99a7bc1fc1810f76 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@bootlin.com> +Date: Wed, 19 Jun 2019 12:17:49 +0200 +Subject: [PATCH] drm/modes: Rewrite the command line parser +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit e08ab74bd4c7a5fe311bc05f32dbb4f1e7fa3428 upstream. + +Rewrite the command line parser in order to get away from the state machine +parsing the video mode lines. + +Hopefully, this will allow to extend it more easily to support named modes +and / or properties set directly on the command line. + +Reviewed-by: Noralf Trønnes <noralf@tronnes.org> +Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> +Link: https://patchwork.freedesktop.org/patch/msgid/e32cd4009153b184103554009135c7bf7c9975d7.1560783090.git-series.maxime.ripard@bootlin.com +--- + drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++------------- + 1 file changed, 210 insertions(+), 115 deletions(-) + +--- a/drivers/gpu/drm/drm_modes.c ++++ b/drivers/gpu/drm/drm_modes.c +@@ -30,6 +30,7 @@ + * authorization from the copyright holder(s) and author(s). + */ + ++#include <linux/ctype.h> + #include <linux/list.h> + #include <linux/list_sort.h> + #include <linux/export.h> +@@ -1414,6 +1415,151 @@ void drm_connector_list_update(struct dr + } + EXPORT_SYMBOL(drm_connector_list_update); + ++static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr, ++ struct drm_cmdline_mode *mode) ++{ ++ unsigned int bpp; ++ ++ if (str[0] != '-') ++ return -EINVAL; ++ ++ str++; ++ bpp = simple_strtol(str, end_ptr, 10); ++ if (*end_ptr == str) ++ return -EINVAL; ++ ++ mode->bpp = bpp; ++ mode->bpp_specified = true; ++ ++ return 0; ++} ++ ++static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr, ++ struct drm_cmdline_mode *mode) ++{ ++ unsigned int refresh; ++ ++ if (str[0] != '@') ++ return -EINVAL; ++ ++ str++; ++ refresh = simple_strtol(str, end_ptr, 10); ++ if (*end_ptr == str) ++ return -EINVAL; ++ ++ mode->refresh = refresh; ++ mode->refresh_specified = true; ++ ++ return 0; ++} ++ ++static int drm_mode_parse_cmdline_extra(const char *str, int length, ++ struct drm_connector *connector, ++ struct drm_cmdline_mode *mode) ++{ ++ int i; ++ ++ for (i = 0; i < length; i++) { ++ switch (str[i]) { ++ case 'i': ++ mode->interlace = true; ++ break; ++ case 'm': ++ mode->margins = true; ++ break; ++ case 'D': ++ if (mode->force != DRM_FORCE_UNSPECIFIED) ++ return -EINVAL; ++ ++ if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) && ++ (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB)) ++ mode->force = DRM_FORCE_ON; ++ else ++ mode->force = DRM_FORCE_ON_DIGITAL; ++ break; ++ case 'd': ++ if (mode->force != DRM_FORCE_UNSPECIFIED) ++ return -EINVAL; ++ ++ mode->force = DRM_FORCE_OFF; ++ break; ++ case 'e': ++ if (mode->force != DRM_FORCE_UNSPECIFIED) ++ return -EINVAL; ++ ++ mode->force = DRM_FORCE_ON; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, ++ bool extras, ++ struct drm_connector *connector, ++ struct drm_cmdline_mode *mode) ++{ ++ const char *str_start = str; ++ bool rb = false, cvt = false; ++ int xres = 0, yres = 0; ++ int remaining, i; ++ char *end_ptr; ++ ++ xres = simple_strtol(str, &end_ptr, 10); ++ if (end_ptr == str) ++ return -EINVAL; ++ ++ if (end_ptr[0] != 'x') ++ return -EINVAL; ++ end_ptr++; ++ ++ str = end_ptr; ++ yres = simple_strtol(str, &end_ptr, 10); ++ if (end_ptr == str) ++ return -EINVAL; ++ ++ remaining = length - (end_ptr - str_start); ++ if (remaining < 0) ++ return -EINVAL; ++ ++ for (i = 0; i < remaining; i++) { ++ switch (end_ptr[i]) { ++ case 'M': ++ cvt = true; ++ break; ++ case 'R': ++ rb = true; ++ break; ++ default: ++ /* ++ * Try to pass that to our extras parsing ++ * function to handle the case where the ++ * extras are directly after the resolution ++ */ ++ if (extras) { ++ int ret = drm_mode_parse_cmdline_extra(end_ptr + i, ++ 1, ++ connector, ++ mode); ++ if (ret) ++ return ret; ++ } else { ++ return -EINVAL; ++ } ++ } ++ } ++ ++ mode->xres = xres; ++ mode->yres = yres; ++ mode->cvt = cvt; ++ mode->rb = rb; ++ ++ return 0; ++} ++ + /** + * drm_mode_parse_command_line_for_connector - parse command line modeline for connector + * @mode_option: optional per connector mode option +@@ -1440,13 +1586,12 @@ bool drm_mode_parse_command_line_for_con + struct drm_cmdline_mode *mode) + { + const char *name; +- unsigned int namelen; +- bool res_specified = false, bpp_specified = false, refresh_specified = false; +- unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0; +- bool yres_specified = false, cvt = false, rb = false; +- bool interlace = false, margins = false, was_digit = false; +- int i; +- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; ++ bool parse_extras = false; ++ unsigned int bpp_off = 0, refresh_off = 0; ++ unsigned int mode_end = 0; ++ char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; ++ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL; ++ int ret; + + #ifdef CONFIG_FB + if (!mode_option) +@@ -1459,127 +1604,77 @@ bool drm_mode_parse_command_line_for_con + } + + name = mode_option; +- namelen = strlen(name); +- for (i = namelen-1; i >= 0; i--) { +- switch (name[i]) { +- case '@': +- if (!refresh_specified && !bpp_specified && +- !yres_specified && !cvt && !rb && was_digit) { +- refresh = simple_strtol(&name[i+1], NULL, 10); +- refresh_specified = true; +- was_digit = false; +- } else +- goto done; +- break; +- case '-': +- if (!bpp_specified && !yres_specified && !cvt && +- !rb && was_digit) { +- bpp = simple_strtol(&name[i+1], NULL, 10); +- bpp_specified = true; +- was_digit = false; +- } else +- goto done; +- break; +- case 'x': +- if (!yres_specified && was_digit) { +- yres = simple_strtol(&name[i+1], NULL, 10); +- yres_specified = true; +- was_digit = false; +- } else +- goto done; +- break; +- case '0' ... '9': +- was_digit = true; +- break; +- case 'M': +- if (yres_specified || cvt || was_digit) +- goto done; +- cvt = true; +- break; +- case 'R': +- if (yres_specified || cvt || rb || was_digit) +- goto done; +- rb = true; +- break; +- case 'm': +- if (cvt || yres_specified || was_digit) +- goto done; +- margins = true; +- break; +- case 'i': +- if (cvt || yres_specified || was_digit) +- goto done; +- interlace = true; +- break; +- case 'e': +- if (yres_specified || bpp_specified || refresh_specified || +- was_digit || (force != DRM_FORCE_UNSPECIFIED)) +- goto done; + +- force = DRM_FORCE_ON; +- break; +- case 'D': +- if (yres_specified || bpp_specified || refresh_specified || +- was_digit || (force != DRM_FORCE_UNSPECIFIED)) +- goto done; ++ if (!isdigit(name[0])) ++ return false; + +- if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) && +- (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB)) +- force = DRM_FORCE_ON; +- else +- force = DRM_FORCE_ON_DIGITAL; +- break; +- case 'd': +- if (yres_specified || bpp_specified || refresh_specified || +- was_digit || (force != DRM_FORCE_UNSPECIFIED)) +- goto done; ++ /* Try to locate the bpp and refresh specifiers, if any */ ++ bpp_ptr = strchr(name, '-'); ++ if (bpp_ptr) { ++ bpp_off = bpp_ptr - name; ++ mode->bpp_specified = true; ++ } + +- force = DRM_FORCE_OFF; +- break; +- default: +- goto done; +- } ++ refresh_ptr = strchr(name, '@'); ++ if (refresh_ptr) { ++ refresh_off = refresh_ptr - name; ++ mode->refresh_specified = true; + } + +- if (i < 0 && yres_specified) { +- char *ch; +- xres = simple_strtol(name, &ch, 10); +- if ((ch != NULL) && (*ch == 'x')) +- res_specified = true; +- else +- i = ch - name; +- } else if (!yres_specified && was_digit) { +- /* catch mode that begins with digits but has no 'x' */ +- i = 0; +- } +-done: +- if (i >= 0) { +- pr_warn("[drm] parse error at position %i in video mode '%s'\n", +- i, name); +- mode->specified = false; +- return false; ++ /* Locate the end of the name / resolution, and parse it */ ++ if (bpp_ptr && refresh_ptr) { ++ mode_end = min(bpp_off, refresh_off); ++ } else if (bpp_ptr) { ++ mode_end = bpp_off; ++ } else if (refresh_ptr) { ++ mode_end = refresh_off; ++ } else { ++ mode_end = strlen(name); ++ parse_extras = true; + } + +- if (res_specified) { +- mode->specified = true; +- mode->xres = xres; +- mode->yres = yres; ++ ret = drm_mode_parse_cmdline_res_mode(name, mode_end, ++ parse_extras, ++ connector, ++ mode); ++ if (ret) ++ return false; ++ mode->specified = true; ++ ++ if (bpp_ptr) { ++ ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode); ++ if (ret) ++ return false; + } + +- if (refresh_specified) { +- mode->refresh_specified = true; +- mode->refresh = refresh; ++ if (refresh_ptr) { ++ ret = drm_mode_parse_cmdline_refresh(refresh_ptr, ++ &refresh_end_ptr, mode); ++ if (ret) ++ return false; + } + +- if (bpp_specified) { +- mode->bpp_specified = true; +- mode->bpp = bpp; ++ /* ++ * Locate the end of the bpp / refresh, and parse the extras ++ * if relevant ++ */ ++ if (bpp_ptr && refresh_ptr) ++ extra_ptr = max(bpp_end_ptr, refresh_end_ptr); ++ else if (bpp_ptr) ++ extra_ptr = bpp_end_ptr; ++ else if (refresh_ptr) ++ extra_ptr = refresh_end_ptr; ++ ++ if (extra_ptr) { ++ int remaining = strlen(name) - (extra_ptr - name); ++ ++ /* ++ * We still have characters to process, while ++ * we shouldn't have any ++ */ ++ if (remaining > 0) ++ return false; + } +- mode->rb = rb; +- mode->cvt = cvt; +- mode->interlace = interlace; +- mode->margins = margins; +- mode->force = force; + + return true; + } |