1 From 3508a8548f13be68b6d098ad99a7bc1fc1810f76 Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime.ripard@bootlin.com>
3 Date: Wed, 19 Jun 2019 12:17:49 +0200
4 Subject: [PATCH] drm/modes: Rewrite the command line parser
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 commit e08ab74bd4c7a5fe311bc05f32dbb4f1e7fa3428 upstream.
11 Rewrite the command line parser in order to get away from the state machine
12 parsing the video mode lines.
14 Hopefully, this will allow to extend it more easily to support named modes
15 and / or properties set directly on the command line.
17 Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
18 Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
19 Link: https://patchwork.freedesktop.org/patch/msgid/e32cd4009153b184103554009135c7bf7c9975d7.1560783090.git-series.maxime.ripard@bootlin.com
21 drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++-------------
22 1 file changed, 210 insertions(+), 115 deletions(-)
24 --- a/drivers/gpu/drm/drm_modes.c
25 +++ b/drivers/gpu/drm/drm_modes.c
27 * authorization from the copyright holder(s) and author(s).
30 +#include <linux/ctype.h>
31 #include <linux/list.h>
32 #include <linux/list_sort.h>
33 #include <linux/export.h>
34 @@ -1414,6 +1415,151 @@ void drm_connector_list_update(struct dr
36 EXPORT_SYMBOL(drm_connector_list_update);
38 +static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
39 + struct drm_cmdline_mode *mode)
47 + bpp = simple_strtol(str, end_ptr, 10);
48 + if (*end_ptr == str)
52 + mode->bpp_specified = true;
57 +static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
58 + struct drm_cmdline_mode *mode)
60 + unsigned int refresh;
66 + refresh = simple_strtol(str, end_ptr, 10);
67 + if (*end_ptr == str)
70 + mode->refresh = refresh;
71 + mode->refresh_specified = true;
76 +static int drm_mode_parse_cmdline_extra(const char *str, int length,
77 + struct drm_connector *connector,
78 + struct drm_cmdline_mode *mode)
82 + for (i = 0; i < length; i++) {
85 + mode->interlace = true;
88 + mode->margins = true;
91 + if (mode->force != DRM_FORCE_UNSPECIFIED)
94 + if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
95 + (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
96 + mode->force = DRM_FORCE_ON;
98 + mode->force = DRM_FORCE_ON_DIGITAL;
101 + if (mode->force != DRM_FORCE_UNSPECIFIED)
104 + mode->force = DRM_FORCE_OFF;
107 + if (mode->force != DRM_FORCE_UNSPECIFIED)
110 + mode->force = DRM_FORCE_ON;
120 +static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
122 + struct drm_connector *connector,
123 + struct drm_cmdline_mode *mode)
125 + const char *str_start = str;
126 + bool rb = false, cvt = false;
127 + int xres = 0, yres = 0;
131 + xres = simple_strtol(str, &end_ptr, 10);
132 + if (end_ptr == str)
135 + if (end_ptr[0] != 'x')
140 + yres = simple_strtol(str, &end_ptr, 10);
141 + if (end_ptr == str)
144 + remaining = length - (end_ptr - str_start);
148 + for (i = 0; i < remaining; i++) {
149 + switch (end_ptr[i]) {
158 + * Try to pass that to our extras parsing
159 + * function to handle the case where the
160 + * extras are directly after the resolution
163 + int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
184 * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
185 * @mode_option: optional per connector mode option
186 @@ -1440,13 +1586,12 @@ bool drm_mode_parse_command_line_for_con
187 struct drm_cmdline_mode *mode)
190 - unsigned int namelen;
191 - bool res_specified = false, bpp_specified = false, refresh_specified = false;
192 - unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
193 - bool yres_specified = false, cvt = false, rb = false;
194 - bool interlace = false, margins = false, was_digit = false;
196 - enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
197 + bool parse_extras = false;
198 + unsigned int bpp_off = 0, refresh_off = 0;
199 + unsigned int mode_end = 0;
200 + char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
201 + char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
206 @@ -1459,127 +1604,77 @@ bool drm_mode_parse_command_line_for_con
210 - namelen = strlen(name);
211 - for (i = namelen-1; i >= 0; i--) {
214 - if (!refresh_specified && !bpp_specified &&
215 - !yres_specified && !cvt && !rb && was_digit) {
216 - refresh = simple_strtol(&name[i+1], NULL, 10);
217 - refresh_specified = true;
223 - if (!bpp_specified && !yres_specified && !cvt &&
224 - !rb && was_digit) {
225 - bpp = simple_strtol(&name[i+1], NULL, 10);
226 - bpp_specified = true;
232 - if (!yres_specified && was_digit) {
233 - yres = simple_strtol(&name[i+1], NULL, 10);
234 - yres_specified = true;
243 - if (yres_specified || cvt || was_digit)
248 - if (yres_specified || cvt || rb || was_digit)
253 - if (cvt || yres_specified || was_digit)
258 - if (cvt || yres_specified || was_digit)
263 - if (yres_specified || bpp_specified || refresh_specified ||
264 - was_digit || (force != DRM_FORCE_UNSPECIFIED))
267 - force = DRM_FORCE_ON;
270 - if (yres_specified || bpp_specified || refresh_specified ||
271 - was_digit || (force != DRM_FORCE_UNSPECIFIED))
273 + if (!isdigit(name[0]))
276 - if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
277 - (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
278 - force = DRM_FORCE_ON;
280 - force = DRM_FORCE_ON_DIGITAL;
283 - if (yres_specified || bpp_specified || refresh_specified ||
284 - was_digit || (force != DRM_FORCE_UNSPECIFIED))
286 + /* Try to locate the bpp and refresh specifiers, if any */
287 + bpp_ptr = strchr(name, '-');
289 + bpp_off = bpp_ptr - name;
290 + mode->bpp_specified = true;
293 - force = DRM_FORCE_OFF;
298 + refresh_ptr = strchr(name, '@');
300 + refresh_off = refresh_ptr - name;
301 + mode->refresh_specified = true;
304 - if (i < 0 && yres_specified) {
306 - xres = simple_strtol(name, &ch, 10);
307 - if ((ch != NULL) && (*ch == 'x'))
308 - res_specified = true;
311 - } else if (!yres_specified && was_digit) {
312 - /* catch mode that begins with digits but has no 'x' */
317 - pr_warn("[drm] parse error at position %i in video mode '%s'\n",
319 - mode->specified = false;
321 + /* Locate the end of the name / resolution, and parse it */
322 + if (bpp_ptr && refresh_ptr) {
323 + mode_end = min(bpp_off, refresh_off);
324 + } else if (bpp_ptr) {
325 + mode_end = bpp_off;
326 + } else if (refresh_ptr) {
327 + mode_end = refresh_off;
329 + mode_end = strlen(name);
330 + parse_extras = true;
333 - if (res_specified) {
334 - mode->specified = true;
337 + ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
343 + mode->specified = true;
346 + ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
351 - if (refresh_specified) {
352 - mode->refresh_specified = true;
353 - mode->refresh = refresh;
355 + ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
356 + &refresh_end_ptr, mode);
361 - if (bpp_specified) {
362 - mode->bpp_specified = true;
365 + * Locate the end of the bpp / refresh, and parse the extras
368 + if (bpp_ptr && refresh_ptr)
369 + extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
371 + extra_ptr = bpp_end_ptr;
372 + else if (refresh_ptr)
373 + extra_ptr = refresh_end_ptr;
376 + int remaining = strlen(name) - (extra_ptr - name);
379 + * We still have characters to process, while
380 + * we shouldn't have any
387 - mode->interlace = interlace;
388 - mode->margins = margins;
389 - mode->force = force;