Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

DRM: clean up and document parsing of video= parameter

The video= parameter of the DRM drivers supports some additional flags that
the normal fb drivers do not have. They also allow to limit these flags to
specific outputs. Both things were previously undocumented.

Also the parsing of the line had some oddities:
-A lot of misplaced options were silently ignored or partly rejected instead
of stopping the parsing immediately
-The 'R' option is documented to follow the 'M' option if specified. It is not
documented that 'M' is needed to specify 'R' (also this is the case for normal
fb drivers). In fact the code is correct for normal fb drivers but wrong for
DRM ones.
The old code allowed 'R' only _before_ 'M' (since it parses backwards) and only
if 'M' is given at all which is not needed for the DRM drivers.
-the margins option ('m') was parsed but later ignored even if the later
functions support it.
-specifying multiple enable options at the same time did not lead to an error.
-specifying something bogus for horizontal resolution (i.e. other things as
digits) did not lead to an error but an invalid resolution was used.

If any errors are encountered the position of the faulting string is now
printed to the user and the complete mode is ignored. This gives much
more consistent error behaviour.

I also removed some useless assignments and changed the local flag variables
to be bool.

Signed-off-by: Rolf Eike Beer <eike-kernel@sf-tec.de>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Rolf Eike Beer and committed by
Dave Airlie
04fee895 ee276291

+78 -30
+18 -3
Documentation/fb/modedb.txt
··· 20 20 21 21 Valid mode specifiers (mode_option argument): 22 22 23 - <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] 23 + <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd] 24 24 <name>[-<bpp>][@<refresh>] 25 25 26 26 with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string. ··· 35 35 pixels and 1.8% of yres). 36 36 37 37 Sample usage: 1024x768M@60m - CVT timing with margins 38 + 39 + DRM drivers also add options to enable or disable outputs: 40 + 41 + 'e' will force the display to be enabled, i.e. it will override the detection 42 + if a display is connected. 'D' will force the display to be enabled and use 43 + digital output. This is useful for outputs that have both analog and digital 44 + signals (e.g. HDMI and DVI-I). For other outputs it behaves like 'e'. If 'd' 45 + is specified the output is disabled. 46 + 47 + You can additionally specify which output the options matches to. 48 + To force the VGA output to be enabled and drive a specific mode say: 49 + video=VGA-1:1280x1024@60me 50 + 51 + Specifying the option multiple times for different ports is possible, e.g.: 52 + video=LVDS-1:d video=HDMI-1:D 38 53 39 54 ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** 40 55 ··· 147 132 tridentfb - Trident (Cyber)blade chipset frame buffer 148 133 vt8623fb - VIA 8623 frame buffer 149 134 150 - BTW, only a few drivers use this at the moment. Others are to follow 151 - (feel free to send patches). 135 + BTW, only a few fb drivers use this at the moment. Others are to follow 136 + (feel free to send patches). The DRM drivers also support this.
+60 -27
drivers/gpu/drm/drm_modes.c
··· 994 994 { 995 995 const char *name; 996 996 unsigned int namelen; 997 - int res_specified = 0, bpp_specified = 0, refresh_specified = 0; 997 + bool res_specified = false, bpp_specified = false, refresh_specified = false; 998 998 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0; 999 - int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; 999 + bool yres_specified = false, cvt = false, rb = false; 1000 + bool interlace = false, margins = false, was_digit = false; 1000 1001 int i; 1001 1002 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; 1002 1003 ··· 1016 1015 for (i = namelen-1; i >= 0; i--) { 1017 1016 switch (name[i]) { 1018 1017 case '@': 1019 - namelen = i; 1020 1018 if (!refresh_specified && !bpp_specified && 1021 - !yres_specified) { 1019 + !yres_specified && !cvt && !rb && was_digit) { 1022 1020 refresh = simple_strtol(&name[i+1], NULL, 10); 1023 - refresh_specified = 1; 1024 - if (cvt || rb) 1025 - cvt = 0; 1021 + refresh_specified = true; 1022 + was_digit = false; 1026 1023 } else 1027 1024 goto done; 1028 1025 break; 1029 1026 case '-': 1030 - namelen = i; 1031 - if (!bpp_specified && !yres_specified) { 1027 + if (!bpp_specified && !yres_specified && !cvt && 1028 + !rb && was_digit) { 1032 1029 bpp = simple_strtol(&name[i+1], NULL, 10); 1033 - bpp_specified = 1; 1034 - if (cvt || rb) 1035 - cvt = 0; 1030 + bpp_specified = true; 1031 + was_digit = false; 1036 1032 } else 1037 1033 goto done; 1038 1034 break; 1039 1035 case 'x': 1040 - if (!yres_specified) { 1036 + if (!yres_specified && was_digit) { 1041 1037 yres = simple_strtol(&name[i+1], NULL, 10); 1042 - yres_specified = 1; 1038 + yres_specified = true; 1039 + was_digit = false; 1043 1040 } else 1044 1041 goto done; 1045 1042 case '0' ... '9': 1043 + was_digit = true; 1046 1044 break; 1047 1045 case 'M': 1048 - if (!yres_specified) 1049 - cvt = 1; 1046 + if (yres_specified || cvt || was_digit) 1047 + goto done; 1048 + cvt = true; 1050 1049 break; 1051 1050 case 'R': 1052 - if (cvt) 1053 - rb = 1; 1051 + if (yres_specified || cvt || rb || was_digit) 1052 + goto done; 1053 + rb = true; 1054 1054 break; 1055 1055 case 'm': 1056 - if (!cvt) 1057 - margins = 1; 1056 + if (cvt || yres_specified || was_digit) 1057 + goto done; 1058 + margins = true; 1058 1059 break; 1059 1060 case 'i': 1060 - if (!cvt) 1061 - interlace = 1; 1061 + if (cvt || yres_specified || was_digit) 1062 + goto done; 1063 + interlace = true; 1062 1064 break; 1063 1065 case 'e': 1066 + if (yres_specified || bpp_specified || refresh_specified || 1067 + was_digit || (force != DRM_FORCE_UNSPECIFIED)) 1068 + goto done; 1069 + 1064 1070 force = DRM_FORCE_ON; 1065 1071 break; 1066 1072 case 'D': 1073 + if (yres_specified || bpp_specified || refresh_specified || 1074 + was_digit || (force != DRM_FORCE_UNSPECIFIED)) 1075 + goto done; 1076 + 1067 1077 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) && 1068 1078 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB)) 1069 1079 force = DRM_FORCE_ON; ··· 1082 1070 force = DRM_FORCE_ON_DIGITAL; 1083 1071 break; 1084 1072 case 'd': 1073 + if (yres_specified || bpp_specified || refresh_specified || 1074 + was_digit || (force != DRM_FORCE_UNSPECIFIED)) 1075 + goto done; 1076 + 1085 1077 force = DRM_FORCE_OFF; 1086 1078 break; 1087 1079 default: 1088 1080 goto done; 1089 1081 } 1090 1082 } 1083 + 1091 1084 if (i < 0 && yres_specified) { 1092 - xres = simple_strtol(name, NULL, 10); 1093 - res_specified = 1; 1085 + char *ch; 1086 + xres = simple_strtol(name, &ch, 10); 1087 + if ((ch != NULL) && (*ch == 'x')) 1088 + res_specified = true; 1089 + else 1090 + i = ch - name; 1091 + } else if (!yres_specified && was_digit) { 1092 + /* catch mode that begins with digits but has no 'x' */ 1093 + i = 0; 1094 1094 } 1095 1095 done: 1096 + if (i >= 0) { 1097 + printk(KERN_WARNING 1098 + "parse error at position %i in video mode '%s'\n", 1099 + i, name); 1100 + mode->specified = false; 1101 + return false; 1102 + } 1103 + 1096 1104 if (res_specified) { 1097 1105 mode->specified = true; 1098 1106 mode->xres = xres; ··· 1128 1096 mode->bpp_specified = true; 1129 1097 mode->bpp = bpp; 1130 1098 } 1131 - mode->rb = rb ? true : false; 1132 - mode->cvt = cvt ? true : false; 1133 - mode->interlace = interlace ? true : false; 1099 + mode->rb = rb; 1100 + mode->cvt = cvt; 1101 + mode->interlace = interlace; 1102 + mode->margins = margins; 1134 1103 mode->force = force; 1135 1104 1136 1105 return true;