diff options
Diffstat (limited to 'drivers/video/fbmon.c')
-rw-r--r-- | drivers/video/fbmon.c | 169 |
1 files changed, 113 insertions, 56 deletions
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 6b385c39b8b5..438b9411905c 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -48,8 +48,9 @@ | |||
48 | #define DPRINTK(fmt, args...) | 48 | #define DPRINTK(fmt, args...) |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | #define FBMON_FIX_HEADER 1 | 51 | #define FBMON_FIX_HEADER 1 |
52 | #define FBMON_FIX_INPUT 2 | 52 | #define FBMON_FIX_INPUT 2 |
53 | #define FBMON_FIX_TIMINGS 3 | ||
53 | 54 | ||
54 | #ifdef CONFIG_FB_MODE_HELPERS | 55 | #ifdef CONFIG_FB_MODE_HELPERS |
55 | struct broken_edid { | 56 | struct broken_edid { |
@@ -71,6 +72,12 @@ static const struct broken_edid brokendb[] = { | |||
71 | .model = 0x5a44, | 72 | .model = 0x5a44, |
72 | .fix = FBMON_FIX_INPUT, | 73 | .fix = FBMON_FIX_INPUT, |
73 | }, | 74 | }, |
75 | /* Sharp UXGA? */ | ||
76 | { | ||
77 | .manufacturer = "SHP", | ||
78 | .model = 0x138e, | ||
79 | .fix = FBMON_FIX_TIMINGS, | ||
80 | }, | ||
74 | }; | 81 | }; |
75 | 82 | ||
76 | static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, | 83 | static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, |
@@ -87,6 +94,55 @@ static void copy_string(unsigned char *c, unsigned char *s) | |||
87 | while (i-- && (*--s == 0x20)) *s = 0; | 94 | while (i-- && (*--s == 0x20)) *s = 0; |
88 | } | 95 | } |
89 | 96 | ||
97 | static int edid_is_serial_block(unsigned char *block) | ||
98 | { | ||
99 | if ((block[0] == 0x00) && (block[1] == 0x00) && | ||
100 | (block[2] == 0x00) && (block[3] == 0xff) && | ||
101 | (block[4] == 0x00)) | ||
102 | return 1; | ||
103 | else | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int edid_is_ascii_block(unsigned char *block) | ||
108 | { | ||
109 | if ((block[0] == 0x00) && (block[1] == 0x00) && | ||
110 | (block[2] == 0x00) && (block[3] == 0xfe) && | ||
111 | (block[4] == 0x00)) | ||
112 | return 1; | ||
113 | else | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int edid_is_limits_block(unsigned char *block) | ||
118 | { | ||
119 | if ((block[0] == 0x00) && (block[1] == 0x00) && | ||
120 | (block[2] == 0x00) && (block[3] == 0xfd) && | ||
121 | (block[4] == 0x00)) | ||
122 | return 1; | ||
123 | else | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int edid_is_monitor_block(unsigned char *block) | ||
128 | { | ||
129 | if ((block[0] == 0x00) && (block[1] == 0x00) && | ||
130 | (block[2] == 0x00) && (block[3] == 0xfc) && | ||
131 | (block[4] == 0x00)) | ||
132 | return 1; | ||
133 | else | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int edid_is_timing_block(unsigned char *block) | ||
138 | { | ||
139 | if ((block[0] != 0x00) || (block[1] != 0x00) || | ||
140 | (block[2] != 0x00) || (block[4] != 0x00)) | ||
141 | return 1; | ||
142 | else | ||
143 | return 0; | ||
144 | } | ||
145 | |||
90 | static int check_edid(unsigned char *edid) | 146 | static int check_edid(unsigned char *edid) |
91 | { | 147 | { |
92 | unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4]; | 148 | unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4]; |
@@ -104,9 +160,6 @@ static int check_edid(unsigned char *edid) | |||
104 | for (i = 0; i < ARRAY_SIZE(brokendb); i++) { | 160 | for (i = 0; i < ARRAY_SIZE(brokendb); i++) { |
105 | if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) && | 161 | if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) && |
106 | brokendb[i].model == model) { | 162 | brokendb[i].model == model) { |
107 | printk("fbmon: The EDID Block of " | ||
108 | "Manufacturer: %s Model: 0x%x is known to " | ||
109 | "be broken,\n", manufacturer, model); | ||
110 | fix = brokendb[i].fix; | 163 | fix = brokendb[i].fix; |
111 | break; | 164 | break; |
112 | } | 165 | } |
@@ -115,8 +168,10 @@ static int check_edid(unsigned char *edid) | |||
115 | switch (fix) { | 168 | switch (fix) { |
116 | case FBMON_FIX_HEADER: | 169 | case FBMON_FIX_HEADER: |
117 | for (i = 0; i < 8; i++) { | 170 | for (i = 0; i < 8; i++) { |
118 | if (edid[i] != edid_v1_header[i]) | 171 | if (edid[i] != edid_v1_header[i]) { |
119 | ret = fix; | 172 | ret = fix; |
173 | break; | ||
174 | } | ||
120 | } | 175 | } |
121 | break; | 176 | break; |
122 | case FBMON_FIX_INPUT: | 177 | case FBMON_FIX_INPUT: |
@@ -126,14 +181,34 @@ static int check_edid(unsigned char *edid) | |||
126 | if (b[4] & 0x01 && b[0] & 0x80) | 181 | if (b[4] & 0x01 && b[0] & 0x80) |
127 | ret = fix; | 182 | ret = fix; |
128 | break; | 183 | break; |
184 | case FBMON_FIX_TIMINGS: | ||
185 | b = edid + DETAILED_TIMING_DESCRIPTIONS_START; | ||
186 | ret = fix; | ||
187 | |||
188 | for (i = 0; i < 4; i++) { | ||
189 | if (edid_is_limits_block(b)) { | ||
190 | ret = 0; | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | b += DETAILED_TIMING_DESCRIPTION_SIZE; | ||
195 | } | ||
196 | |||
197 | break; | ||
129 | } | 198 | } |
130 | 199 | ||
200 | if (ret) | ||
201 | printk("fbmon: The EDID Block of " | ||
202 | "Manufacturer: %s Model: 0x%x is known to " | ||
203 | "be broken,\n", manufacturer, model); | ||
204 | |||
131 | return ret; | 205 | return ret; |
132 | } | 206 | } |
133 | 207 | ||
134 | static void fix_edid(unsigned char *edid, int fix) | 208 | static void fix_edid(unsigned char *edid, int fix) |
135 | { | 209 | { |
136 | unsigned char *b; | 210 | int i; |
211 | unsigned char *b, csum = 0; | ||
137 | 212 | ||
138 | switch (fix) { | 213 | switch (fix) { |
139 | case FBMON_FIX_HEADER: | 214 | case FBMON_FIX_HEADER: |
@@ -145,6 +220,37 @@ static void fix_edid(unsigned char *edid, int fix) | |||
145 | b = edid + EDID_STRUCT_DISPLAY; | 220 | b = edid + EDID_STRUCT_DISPLAY; |
146 | b[0] &= ~0x80; | 221 | b[0] &= ~0x80; |
147 | edid[127] += 0x80; | 222 | edid[127] += 0x80; |
223 | break; | ||
224 | case FBMON_FIX_TIMINGS: | ||
225 | printk("fbmon: trying to fix monitor timings\n"); | ||
226 | b = edid + DETAILED_TIMING_DESCRIPTIONS_START; | ||
227 | for (i = 0; i < 4; i++) { | ||
228 | if (!(edid_is_serial_block(b) || | ||
229 | edid_is_ascii_block(b) || | ||
230 | edid_is_monitor_block(b) || | ||
231 | edid_is_timing_block(b))) { | ||
232 | b[0] = 0x00; | ||
233 | b[1] = 0x00; | ||
234 | b[2] = 0x00; | ||
235 | b[3] = 0xfd; | ||
236 | b[4] = 0x00; | ||
237 | b[5] = 60; /* vfmin */ | ||
238 | b[6] = 60; /* vfmax */ | ||
239 | b[7] = 30; /* hfmin */ | ||
240 | b[8] = 75; /* hfmax */ | ||
241 | b[9] = 17; /* pixclock - 170 MHz*/ | ||
242 | b[10] = 0; /* GTF */ | ||
243 | break; | ||
244 | } | ||
245 | |||
246 | b += DETAILED_TIMING_DESCRIPTION_SIZE; | ||
247 | } | ||
248 | |||
249 | for (i = 0; i < EDID_LENGTH - 1; i++) | ||
250 | csum += edid[i]; | ||
251 | |||
252 | edid[127] = 256 - csum; | ||
253 | break; | ||
148 | } | 254 | } |
149 | } | 255 | } |
150 | 256 | ||
@@ -273,46 +379,6 @@ static void get_chroma(unsigned char *block, struct fb_monspecs *specs) | |||
273 | DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey); | 379 | DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey); |
274 | } | 380 | } |
275 | 381 | ||
276 | static int edid_is_serial_block(unsigned char *block) | ||
277 | { | ||
278 | if ((block[0] == 0x00) && (block[1] == 0x00) && | ||
279 | (block[2] == 0x00) && (block[3] == 0xff) && | ||
280 | (block[4] == 0x00)) | ||
281 | return 1; | ||
282 | else | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int edid_is_ascii_block(unsigned char *block) | ||
287 | { | ||
288 | if ((block[0] == 0x00) && (block[1] == 0x00) && | ||
289 | (block[2] == 0x00) && (block[3] == 0xfe) && | ||
290 | (block[4] == 0x00)) | ||
291 | return 1; | ||
292 | else | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int edid_is_limits_block(unsigned char *block) | ||
297 | { | ||
298 | if ((block[0] == 0x00) && (block[1] == 0x00) && | ||
299 | (block[2] == 0x00) && (block[3] == 0xfd) && | ||
300 | (block[4] == 0x00)) | ||
301 | return 1; | ||
302 | else | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int edid_is_monitor_block(unsigned char *block) | ||
307 | { | ||
308 | if ((block[0] == 0x00) && (block[1] == 0x00) && | ||
309 | (block[2] == 0x00) && (block[3] == 0xfc) && | ||
310 | (block[4] == 0x00)) | ||
311 | return 1; | ||
312 | else | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static void calc_mode_timings(int xres, int yres, int refresh, | 382 | static void calc_mode_timings(int xres, int yres, int refresh, |
317 | struct fb_videomode *mode) | 383 | struct fb_videomode *mode) |
318 | { | 384 | { |
@@ -795,15 +861,6 @@ static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
795 | } | 861 | } |
796 | } | 862 | } |
797 | 863 | ||
798 | static int edid_is_timing_block(unsigned char *block) | ||
799 | { | ||
800 | if ((block[0] != 0x00) || (block[1] != 0x00) || | ||
801 | (block[2] != 0x00) || (block[4] != 0x00)) | ||
802 | return 1; | ||
803 | else | ||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) | 864 | int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) |
808 | { | 865 | { |
809 | int i; | 866 | int i; |