@@ -149,6 +149,10 @@ drm_connector_pick_cmdline_mode(struct drm_connector *connector)
prefer_non_interlace = !cmdline_mode->interlace;
again:
list_for_each_entry(mode, &connector->modes, head) {
+ /* Check (optional) mode name first */
+ if (!strcmp(mode->name, cmdline_mode->name))
+ return mode;
+
/* check width/height */
if (mode->hdisplay != cmdline_mode->xres ||
mode->vdisplay != cmdline_mode->yres)
@@ -139,8 +139,9 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
connector->force = mode->force;
}
- DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+ DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
connector->name,
+ mode->name ? mode->name : "",
mode->xres, mode->yres,
mode->refresh_specified ? mode->refresh : 60,
mode->rb ? " reduced blanking" : "",
@@ -1580,7 +1580,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
struct drm_cmdline_mode *mode)
{
const char *name;
- bool parse_extras = false;
+ bool named_mode = false, 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;
@@ -1599,8 +1599,22 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
name = mode_option;
- if (!isdigit(name[0]))
- return false;
+ /*
+ * This is a bit convoluted. To differentiate between the
+ * named modes and poorly formatted resolutions, we need a
+ * bunch of things:
+ * - We need to make sure that the first character (which
+ * would be our resolution in X) is a digit.
+ * - However, if the X resolution is missing, then we end up
+ * with something like x<yres>, with our first character
+ * being an alpha-numerical character, which would be
+ * considered a named mode.
+ *
+ * If this isn't enough, we should add more heuristics here,
+ * and matching unit-tests.
+ */
+ if (!isdigit(name[0]) && name[0] != 'x')
+ named_mode = true;
/* Try to locate the bpp and refresh specifiers, if any */
bpp_ptr = strchr(name, '-');
@@ -1611,6 +1625,9 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
refresh_ptr = strchr(name, '@');
if (refresh_ptr) {
+ if (named_mode)
+ return false;
+
refresh_off = refresh_ptr - name;
mode->refresh_specified = true;
}
@@ -1627,12 +1644,16 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
parse_extras = true;
}
- ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
- parse_extras,
- connector,
- mode);
- if (ret)
- return false;
+ if (named_mode) {
+ strncpy(mode->name, name, mode_end);
+ } else {
+ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+ parse_extras,
+ connector,
+ mode);
+ if (ret)
+ return false;
+ }
mode->specified = true;
if (bpp_ptr) {
@@ -1660,14 +1681,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
extra_ptr = refresh_end_ptr;
if (extra_ptr) {
- int remaining = strlen(name) - (extra_ptr - name);
+ if (!named_mode) {
+ int len = strlen(name) - (extra_ptr - name);
- /*
- * We still have characters to process, while
- * we shouldn't have any
- */
- if (remaining > 0)
- return false;
+ ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
+ connector, mode);
+ if (ret)
+ return false;
+ } else {
+ int remaining = strlen(name) - (extra_ptr - name);
+
+ /*
+ * We still have characters to process, while
+ * we shouldn't have any
+ */
+ if (remaining > 0)
+ return false;
+ }
}
return true;
@@ -914,6 +914,13 @@ struct drm_connector_funcs {
*/
struct drm_cmdline_mode {
/**
+ * @name:
+ *
+ * Name of the mode.
+ */
+ char name[DRM_DISPLAY_MODE_LEN];
+
+ /**
* @specified:
*
* Has a mode been read from the command-line?