LCOV - code coverage report
Current view: top level - dev/videomode - edid.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 325 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $NetBSD: edid.c,v 1.5 2007/03/07 19:56:40 macallan Exp $ */
       2             : 
       3             : /*-
       4             :  * Copyright (c) 2006 Itronix Inc.
       5             :  * All rights reserved.
       6             :  *
       7             :  * Written by Garrett D'Amore for Itronix Inc.
       8             :  *
       9             :  * Redistribution and use in source and binary forms, with or without
      10             :  * modification, are permitted provided that the following conditions
      11             :  * are met:
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  * 2. Redistributions in binary form must reproduce the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer in the
      16             :  *    documentation and/or other materials provided with the distribution.
      17             :  * 3. The name of Itronix Inc. may not be used to endorse
      18             :  *    or promote products derived from this software without specific
      19             :  *    prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
      22             :  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      23             :  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
      25             :  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
      27             :  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      28             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      29             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      30             :  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      31             :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      32             :  */ 
      33             : 
      34             : #include <sys/param.h>
      35             : #include <sys/systm.h>
      36             : #include <sys/device.h>
      37             : #include <sys/kernel.h>
      38             : #include <sys/malloc.h>
      39             : #include <dev/videomode/videomode.h>
      40             : #include <dev/videomode/ediddevs.h>
      41             : #include <dev/videomode/edidreg.h>
      42             : #include <dev/videomode/edidvar.h>
      43             : #include <dev/videomode/vesagtf.h>
      44             : 
      45             : const char *edid_findvendor(const char *);
      46             : const char *edid_findproduct(const char *, uint16_t);
      47             : void edid_strchomp(char *);
      48             : const struct videomode *edid_mode_lookup_list(const char *);
      49             : int edid_std_timing(uint8_t *, struct videomode *);
      50             : int edid_det_timing(uint8_t *, struct videomode *);
      51             : void edid_block(struct edid_info *, uint8_t *);
      52             : 
      53             : #define EDIDVERBOSE     1
      54             : #define DIVIDE(x,y)     (((x) + ((y) / 2)) / (y))
      55             : 
      56             : static const char *_edid_modes[] =  {
      57             :         "1280x1024x75",
      58             :         "1024x768x75",
      59             :         "1024x768x70",
      60             :         "1024x768x60",
      61             :         "1024x768x87i",
      62             :         "832x768x74", /* rounding error, 74.55 Hz aka "832x624x75" */
      63             :         "800x600x75",
      64             :         "800x600x72",
      65             :         "800x600x60",
      66             :         "800x600x56",
      67             :         "640x480x75",
      68             :         "640x480x72",
      69             :         "640x480x67",
      70             :         "640x480x60",
      71             :         "720x400x85", /* should this really be "720x400x88" ? */
      72             :         "720x400x70", /* hmm... videmode.c doesn't have this one */
      73             : };
      74             : 
      75             : #ifdef  EDIDVERBOSE
      76             : struct edid_vendor {
      77             :         const char      *vendor;
      78             :         const char      *name;
      79             : };
      80             : 
      81             : struct edid_product {
      82             :         const char      *vendor;
      83             :         uint16_t        product;
      84             :         const char      *name;
      85             : };
      86             : 
      87             : #include <dev/videomode/ediddevs_data.h>
      88             : #endif  /* EDIDVERBOSE */
      89             : 
      90             : const char *
      91           0 : edid_findvendor(const char *vendor)
      92             : {
      93             : #ifdef  EDIDVERBOSE
      94             :         int     n;
      95             : 
      96           0 :         for (n = 0; n < edid_nvendors; n++)
      97           0 :                 if (memcmp(edid_vendors[n].vendor, vendor, 3) == 0)
      98           0 :                         return (edid_vendors[n].name);
      99             : #endif
     100           0 :         return NULL;
     101           0 : }
     102             : 
     103             : const char *
     104           0 : edid_findproduct(const char *vendor, uint16_t product)
     105             : {
     106             : #ifdef  EDIDVERBOSE
     107             :         int     n;
     108             : 
     109           0 :         for (n = 0; n < edid_nproducts; n++)
     110           0 :                 if ((edid_products[n].product == product) &&
     111           0 :                     (memcmp(edid_products[n].vendor, vendor, 3) == 0))
     112           0 :                         return (edid_products[n].name);
     113             : #endif  /* EDIDVERBOSE */
     114           0 :         return NULL;
     115             : 
     116           0 : }
     117             : 
     118             : void
     119           0 : edid_strchomp(char *ptr)
     120             : {
     121           0 :         for (;;) {
     122           0 :                 switch (*ptr) {
     123             :                 case 0:
     124             :                         return;
     125             :                 case '\r':
     126             :                 case '\n':
     127           0 :                         *ptr = 0;
     128           0 :                         return;
     129             :                 }
     130           0 :                 ptr++;
     131             :         }
     132           0 : }
     133             : 
     134             : int
     135           0 : edid_is_valid(uint8_t *d)
     136             : {
     137             :         int sum = 0, i;
     138           0 :         uint8_t sig[8] = EDID_SIGNATURE;
     139             :         
     140           0 :         if (memcmp(d, sig, 8) != 0)
     141           0 :                 return EINVAL;
     142             :         
     143           0 :         for (i = 0; i < 128; i++)
     144           0 :                 sum += d[i];
     145           0 :         if ((sum & 0xff) != 0)
     146           0 :                 return EINVAL;
     147             :                 
     148           0 :         return 0;
     149           0 : }
     150             : 
     151             : void
     152           0 : edid_print(struct edid_info *edid)
     153             : {
     154             :         int     i;
     155             : 
     156           0 :         if (edid == NULL)
     157           0 :                 return;
     158           0 :         printf("Vendor: [%s] %s\n", edid->edid_vendor, edid->edid_vendorname);
     159           0 :         printf("Product: [%04X] %s\n", edid->edid_product,
     160           0 :             edid->edid_productname);
     161           0 :         printf("Serial number: %s\n", edid->edid_serial);
     162           0 :         printf("Manufactured %d Week %d\n",
     163           0 :             edid->edid_year, edid->edid_week);
     164           0 :         printf("EDID Version %d.%d\n", edid->edid_version,
     165           0 :             edid->edid_revision);
     166           0 :         printf("EDID Comment: %s\n", edid->edid_comment);
     167             : 
     168           0 :         printf("Video Input: %x\n", edid->edid_video_input);
     169           0 :         if (edid->edid_video_input & EDID_VIDEO_INPUT_DIGITAL) {
     170           0 :                 printf("\tDigital");
     171           0 :                 if (edid->edid_video_input & EDID_VIDEO_INPUT_DFP1_COMPAT)
     172           0 :                         printf(" (DFP 1.x compatible)");
     173           0 :                 printf("\n");
     174           0 :         } else {
     175           0 :                 printf("\tAnalog\n");
     176           0 :                 switch (EDID_VIDEO_INPUT_LEVEL(edid->edid_video_input)) {
     177             :                 case 0:
     178           0 :                         printf("\t-0.7, 0.3V\n");
     179           0 :                         break;
     180             :                 case 1:
     181           0 :                         printf("\t-0.714, 0.286V\n");
     182           0 :                         break;
     183             :                 case 2:
     184           0 :                         printf("\t-1.0, 0.4V\n");
     185           0 :                         break;
     186             :                 case 3:
     187           0 :                         printf("\t-0.7, 0.0V\n");
     188           0 :                         break;
     189             :                 }
     190           0 :                 if (edid->edid_video_input & EDID_VIDEO_INPUT_BLANK_TO_BLACK)
     191           0 :                         printf("\tBlank-to-black setup\n");
     192           0 :                 if (edid->edid_video_input & EDID_VIDEO_INPUT_SEPARATE_SYNCS)
     193           0 :                         printf("\tSeperate syncs\n");
     194           0 :                 if (edid->edid_video_input & EDID_VIDEO_INPUT_COMPOSITE_SYNC)
     195           0 :                         printf("\tComposite sync\n");
     196           0 :                 if (edid->edid_video_input & EDID_VIDEO_INPUT_SYNC_ON_GRN)
     197           0 :                         printf("\tSync on green\n");
     198           0 :                 if (edid->edid_video_input & EDID_VIDEO_INPUT_SERRATION)
     199           0 :                         printf("\tSerration vsync\n");
     200             :         }
     201             : 
     202           0 :         printf("Gamma: %d.%02d\n",
     203           0 :             edid->edid_gamma / 100, edid->edid_gamma % 100);
     204             : 
     205           0 :         printf("Max Size: %d cm x %d cm\n",
     206           0 :             edid->edid_max_hsize, edid->edid_max_vsize);
     207             : 
     208           0 :         printf("Features: %x\n", edid->edid_features);
     209           0 :         if (edid->edid_features & EDID_FEATURES_STANDBY)
     210           0 :                 printf("\tDPMS standby\n");
     211           0 :         if (edid->edid_features & EDID_FEATURES_SUSPEND)
     212           0 :                 printf("\tDPMS suspend\n");
     213           0 :         if (edid->edid_features & EDID_FEATURES_ACTIVE_OFF)
     214           0 :                 printf("\tDPMS active-off\n");
     215           0 :         switch (EDID_FEATURES_DISP_TYPE(edid->edid_features)) {
     216             :         case EDID_FEATURES_DISP_TYPE_MONO:
     217           0 :                 printf("\tMonochrome\n");
     218           0 :                 break;
     219             :         case EDID_FEATURES_DISP_TYPE_RGB:
     220           0 :                 printf("\tRGB\n");
     221           0 :                 break;
     222             :         case EDID_FEATURES_DISP_TYPE_NON_RGB:
     223           0 :                 printf("\tMulticolor\n");
     224           0 :                 break;
     225             :         case EDID_FEATURES_DISP_TYPE_UNDEFINED:
     226           0 :                 printf("\tUndefined monitor type\n");
     227           0 :                 break;
     228             :         }
     229           0 :         if (edid->edid_features & EDID_FEATURES_STD_COLOR)
     230           0 :                 printf("\tStandard color space\n");
     231           0 :         if (edid->edid_features & EDID_FEATURES_PREFERRED_TIMING)
     232           0 :                 printf("\tPreferred timing\n");
     233           0 :         if (edid->edid_features & EDID_FEATURES_DEFAULT_GTF)
     234           0 :                 printf("\tDefault GTF supported\n");
     235             : 
     236           0 :         printf("Chroma Info:\n");
     237           0 :         printf("\tRed X: 0.%03d\n", edid->edid_chroma.ec_redx);
     238           0 :         printf("\tRed Y: 0.%03d\n", edid->edid_chroma.ec_redy);
     239           0 :         printf("\tGrn X: 0.%03d\n", edid->edid_chroma.ec_greenx);
     240           0 :         printf("\tGrn Y: 0.%03d\n", edid->edid_chroma.ec_greeny);
     241           0 :         printf("\tBlu X: 0.%03d\n", edid->edid_chroma.ec_bluex);
     242           0 :         printf("\tBlu Y: 0.%03d\n", edid->edid_chroma.ec_bluey);
     243           0 :         printf("\tWht X: 0.%03d\n", edid->edid_chroma.ec_whitex);
     244           0 :         printf("\tWht Y: 0.%03d\n", edid->edid_chroma.ec_whitey);
     245             : 
     246           0 :         if (edid->edid_have_range) {
     247           0 :                 printf("Range:\n");
     248           0 :                 printf("\tHorizontal: %d - %d kHz\n",
     249           0 :                     edid->edid_range.er_min_hfreq,
     250           0 :                     edid->edid_range.er_max_hfreq);
     251           0 :                 printf("\tVertical: %d - %d Hz\n",
     252           0 :                     edid->edid_range.er_min_vfreq,
     253           0 :                     edid->edid_range.er_max_vfreq);
     254           0 :                 printf("\tMax Dot Clock: %d MHz\n",
     255           0 :                     edid->edid_range.er_max_clock);
     256           0 :                 if (edid->edid_range.er_have_gtf2) {
     257           0 :                         printf("\tGTF2 hfreq: %d\n",
     258           0 :                             edid->edid_range.er_gtf2_hfreq);
     259           0 :                         printf("\tGTF2 C: %d\n", edid->edid_range.er_gtf2_c);
     260           0 :                         printf("\tGTF2 M: %d\n", edid->edid_range.er_gtf2_m);
     261           0 :                         printf("\tGTF2 J: %d\n", edid->edid_range.er_gtf2_j);
     262           0 :                         printf("\tGTF2 K: %d\n", edid->edid_range.er_gtf2_k);
     263           0 :                 }
     264             :         }
     265           0 :         printf("Video modes:\n");
     266           0 :         for (i = 0; i < edid->edid_nmodes; i++) {
     267           0 :                 printf("\t%dx%d @ %dHz\n",
     268           0 :                     edid->edid_modes[i].hdisplay,
     269           0 :                     edid->edid_modes[i].vdisplay,
     270           0 :                     DIVIDE(DIVIDE(edid->edid_modes[i].dot_clock * 1000,
     271             :                                edid->edid_modes[i].htotal),
     272             :                         edid->edid_modes[i].vtotal));
     273             :         }
     274           0 :         if (edid->edid_preferred_mode)
     275           0 :                 printf("Preferred mode: %dx%d @ %dHz\n",
     276           0 :                     edid->edid_preferred_mode->hdisplay,
     277           0 :                     edid->edid_preferred_mode->vdisplay,
     278           0 :                     DIVIDE(DIVIDE(edid->edid_preferred_mode->dot_clock * 1000,
     279             :                                edid->edid_preferred_mode->htotal),
     280             :                         edid->edid_preferred_mode->vtotal));
     281           0 : }
     282             : 
     283             : const struct videomode *
     284           0 : edid_mode_lookup_list(const char *name)
     285             : {
     286             :         int     i;
     287             : 
     288           0 :         for (i = 0; i < videomode_count; i++)
     289           0 :                 if (strcmp(name, videomode_list[i].name) == 0)
     290           0 :                         return &videomode_list[i];
     291           0 :         return NULL;
     292           0 : }
     293             : 
     294             : int
     295           0 : edid_std_timing(uint8_t *data, struct videomode *vmp)
     296             : {
     297             :         unsigned                        x, y, f;
     298             :         const struct videomode          *lookup;
     299           0 :         char                            name[80];
     300             : 
     301           0 :         if ((data[0] == 1 && data[1] == 1) ||
     302           0 :             (data[0] == 0 && data[1] == 0) ||
     303           0 :             (data[0] == 0x20 && data[1] == 0x20))
     304           0 :                 return 0;
     305             : 
     306           0 :         x = EDID_STD_TIMING_HRES(data);
     307           0 :         switch (EDID_STD_TIMING_RATIO(data)) {
     308             :         case EDID_STD_TIMING_RATIO_16_10:
     309           0 :                 y = x * 10 / 16;
     310           0 :                 break;
     311             :         case EDID_STD_TIMING_RATIO_4_3:
     312           0 :                 y = x * 3 / 4;
     313           0 :                 break;
     314             :         case EDID_STD_TIMING_RATIO_5_4:
     315           0 :                 y = x * 4 / 5;
     316           0 :                 break;
     317             :         case EDID_STD_TIMING_RATIO_16_9:
     318             :         default:
     319           0 :                 y = x * 9 / 16;
     320           0 :                 break;
     321             :         }
     322           0 :         f = EDID_STD_TIMING_VFREQ(data);
     323             : 
     324             :         /* first try to lookup the mode as a DMT timing */
     325           0 :         snprintf(name, sizeof (name), "%dx%dx%d", x, y, f);
     326           0 :         if ((lookup = edid_mode_lookup_list(name)) != NULL) {
     327           0 :                 *vmp = *lookup;
     328           0 :         }
     329             : 
     330             :         /* failing that, calculate it using gtf */
     331             :         else {
     332             :                 /*
     333             :                  * Hmm. I'm not using alternate GTF timings, which
     334             :                  * could, in theory, be present.
     335             :                  */
     336           0 :                 vesagtf_mode(x, y, f, vmp);
     337             :         }
     338           0 :         return 1;
     339           0 : }
     340             : 
     341             : int
     342           0 : edid_det_timing(uint8_t *data, struct videomode *vmp)
     343             : {
     344             :         unsigned        hactive, hblank, hsyncwid, hsyncoff;
     345             :         unsigned        vactive, vblank, vsyncwid, vsyncoff;
     346             :         uint8_t         flags;
     347             : 
     348           0 :         flags = EDID_DET_TIMING_FLAGS(data);
     349             : 
     350             :         /* we don't support stereo modes (for now) */
     351           0 :         if (flags & (EDID_DET_TIMING_FLAG_STEREO |
     352             :                 EDID_DET_TIMING_FLAG_STEREO1))
     353           0 :                 return 0;
     354             : 
     355           0 :         vmp->dot_clock = EDID_DET_TIMING_DOT_CLOCK(data) / 1000;
     356             : 
     357           0 :         hactive = EDID_DET_TIMING_HACTIVE(data);
     358           0 :         hblank = EDID_DET_TIMING_HBLANK(data);
     359           0 :         hsyncwid = EDID_DET_TIMING_HSYNC_WIDTH(data);
     360           0 :         hsyncoff = EDID_DET_TIMING_HSYNC_OFFSET(data);
     361             : 
     362           0 :         vactive = EDID_DET_TIMING_VACTIVE(data);
     363           0 :         vblank = EDID_DET_TIMING_VBLANK(data);
     364           0 :         vsyncwid = EDID_DET_TIMING_VSYNC_WIDTH(data);
     365           0 :         vsyncoff = EDID_DET_TIMING_VSYNC_OFFSET(data);
     366             :         
     367             :         /* XXX: I'm not doing anything with the borders, should I? */
     368             : 
     369           0 :         vmp->hdisplay = hactive;
     370           0 :         vmp->htotal = hactive + hblank;
     371           0 :         vmp->hsync_start = hactive + hsyncoff;
     372           0 :         vmp->hsync_end = vmp->hsync_start + hsyncwid;
     373             : 
     374           0 :         vmp->vdisplay = vactive;
     375           0 :         vmp->vtotal = vactive + vblank;
     376           0 :         vmp->vsync_start = vactive + vsyncoff;
     377           0 :         vmp->vsync_end = vmp->vsync_start + vsyncwid;
     378             : 
     379           0 :         vmp->flags = 0;
     380             : 
     381           0 :         if (flags & EDID_DET_TIMING_FLAG_INTERLACE)
     382           0 :                 vmp->flags |= VID_INTERLACE;
     383           0 :         if (flags & EDID_DET_TIMING_FLAG_HSYNC_POSITIVE)
     384           0 :                 vmp->flags |= VID_PHSYNC;
     385             :         else
     386           0 :                 vmp->flags |= VID_NHSYNC;
     387             : 
     388           0 :         if (flags & EDID_DET_TIMING_FLAG_VSYNC_POSITIVE)
     389           0 :                 vmp->flags |= VID_PVSYNC;
     390             :         else
     391           0 :                 vmp->flags |= VID_NVSYNC;
     392             : 
     393           0 :         return 1;
     394           0 : }
     395             : 
     396             : void
     397           0 : edid_block(struct edid_info *edid, uint8_t *data)
     398             : {
     399             :         int                     i;
     400           0 :         struct videomode        mode;
     401             : 
     402           0 :         if (EDID_BLOCK_IS_DET_TIMING(data)) {
     403           0 :                 if (edid_det_timing(data, &mode)) {
     404           0 :                         edid->edid_modes[edid->edid_nmodes] = mode;
     405           0 :                         if (edid->edid_preferred_mode == NULL) {
     406           0 :                                 edid->edid_preferred_mode =
     407           0 :                                     &edid->edid_modes[edid->edid_nmodes];
     408           0 :                         }
     409           0 :                         edid->edid_nmodes++; 
     410           0 :                 }
     411           0 :                 return;
     412             :         }
     413             : 
     414           0 :         switch (EDID_BLOCK_TYPE(data)) {
     415             :         case EDID_DESC_BLOCK_TYPE_SERIAL:
     416           0 :                 memcpy(edid->edid_serial,
     417             :                     data + EDID_DESC_ASCII_DATA_OFFSET,
     418             :                     EDID_DESC_ASCII_DATA_LEN);
     419           0 :                 edid->edid_serial[sizeof (edid->edid_serial) - 1] = 0;
     420           0 :                 break;
     421             : 
     422             :         case EDID_DESC_BLOCK_TYPE_ASCII:
     423           0 :                 memcpy(edid->edid_comment,
     424             :                     data + EDID_DESC_ASCII_DATA_OFFSET,
     425             :                     EDID_DESC_ASCII_DATA_LEN);
     426           0 :                 edid->edid_comment[sizeof (edid->edid_comment) - 1] = 0;
     427           0 :                 break;
     428             : 
     429             :         case EDID_DESC_BLOCK_TYPE_RANGE:
     430           0 :                 edid->edid_have_range = 1;
     431           0 :                 edid->edid_range.er_min_vfreq =      
     432           0 :                     EDID_DESC_RANGE_MIN_VFREQ(data);
     433           0 :                 edid->edid_range.er_max_vfreq =      
     434           0 :                     EDID_DESC_RANGE_MAX_VFREQ(data);
     435           0 :                 edid->edid_range.er_min_hfreq =      
     436           0 :                     EDID_DESC_RANGE_MIN_HFREQ(data);
     437           0 :                 edid->edid_range.er_max_hfreq =      
     438           0 :                     EDID_DESC_RANGE_MAX_HFREQ(data);
     439           0 :                 edid->edid_range.er_max_clock =
     440           0 :                     EDID_DESC_RANGE_MAX_CLOCK(data);
     441           0 :                 if (EDID_DESC_RANGE_HAVE_GTF2(data)) {
     442           0 :                         edid->edid_range.er_have_gtf2 = 1;
     443           0 :                         edid->edid_range.er_gtf2_hfreq =
     444           0 :                             EDID_DESC_RANGE_GTF2_HFREQ(data);
     445           0 :                         edid->edid_range.er_gtf2_c =
     446           0 :                             EDID_DESC_RANGE_GTF2_C(data);
     447           0 :                         edid->edid_range.er_gtf2_m =
     448           0 :                             EDID_DESC_RANGE_GTF2_M(data);
     449           0 :                         edid->edid_range.er_gtf2_j =
     450           0 :                             EDID_DESC_RANGE_GTF2_J(data);
     451           0 :                         edid->edid_range.er_gtf2_k =
     452           0 :                             EDID_DESC_RANGE_GTF2_K(data);
     453           0 :                 }
     454             :                 break;
     455             : 
     456             :         case EDID_DESC_BLOCK_TYPE_NAME:
     457             :                 /* copy the product name into place */
     458           0 :                 memcpy(edid->edid_productname,
     459             :                     data + EDID_DESC_ASCII_DATA_OFFSET,
     460             :                     EDID_DESC_ASCII_DATA_LEN);
     461           0 :                 break;
     462             : 
     463             :         case EDID_DESC_BLOCK_TYPE_STD_TIMING:
     464           0 :                 data += EDID_DESC_STD_TIMING_START;
     465           0 :                 for (i = 0; i < EDID_DESC_STD_TIMING_COUNT; i++) {
     466           0 :                         if (edid_std_timing(data, &mode)) {
     467           0 :                                 edid->edid_modes[edid->edid_nmodes] = mode;
     468           0 :                                 edid->edid_nmodes++;
     469           0 :                         }
     470           0 :                         data += 2;
     471             :                 }
     472             :                 break;
     473             : 
     474             :         case EDID_DESC_BLOCK_TYPE_COLOR_POINT:
     475             :                 /* XXX: not implemented yet */
     476             :                 break;
     477             :         }
     478           0 : }
     479             : 
     480             : /*
     481             :  * Gets EDID version in BCD, e.g. EDID v1.3  returned as 0x0103
     482             :  */
     483             : int
     484           0 : edid_parse(uint8_t *data, struct edid_info *edid)
     485             : {
     486             :         uint16_t                manfid, estmodes;
     487             :         const struct videomode  *vmp;
     488             :         int                     i;
     489             :         const char              *name;
     490             :         int max_dotclock = 0;
     491             :         int mhz;
     492             : 
     493           0 :         if (edid_is_valid(data) != 0)
     494           0 :                 return -1;
     495             : 
     496             :         /* get product identification */
     497           0 :         manfid = EDID_VENDOR_ID(data);
     498           0 :         edid->edid_vendor[0] = EDID_MANFID_0(manfid);
     499           0 :         edid->edid_vendor[1] = EDID_MANFID_1(manfid);
     500           0 :         edid->edid_vendor[2] = EDID_MANFID_2(manfid);
     501           0 :         edid->edid_vendor[3] = 0;    /* null terminate for convenience */
     502             : 
     503           0 :         edid->edid_product = data[EDID_OFFSET_PRODUCT_ID] + 
     504           0 :             (data[EDID_OFFSET_PRODUCT_ID + 1] << 8);
     505             : 
     506           0 :         name = edid_findvendor(edid->edid_vendor);
     507           0 :         if (name != NULL) {
     508           0 :                 snprintf(edid->edid_vendorname,
     509             :                     sizeof (edid->edid_vendorname), "%s", name);
     510           0 :         }
     511           0 :         edid->edid_vendorname[sizeof (edid->edid_vendorname) - 1] = 0;
     512             : 
     513           0 :         name = edid_findproduct(edid->edid_vendor, edid->edid_product);
     514           0 :         if (name != NULL) {
     515           0 :                 snprintf(edid->edid_productname,
     516             :                     sizeof (edid->edid_productname), "%s", name);
     517           0 :         }
     518           0 :         edid->edid_productname[sizeof (edid->edid_productname) - 1] = 0;
     519             : 
     520           0 :         snprintf(edid->edid_serial, sizeof (edid->edid_serial), "%08x",
     521           0 :             EDID_SERIAL_NUMBER(data));
     522             : 
     523           0 :         edid->edid_week = EDID_WEEK(data);
     524           0 :         edid->edid_year = EDID_YEAR(data);
     525             : 
     526             :         /* get edid revision */
     527           0 :         edid->edid_version = EDID_VERSION(data);
     528           0 :         edid->edid_revision = EDID_REVISION(data);
     529             : 
     530           0 :         edid->edid_video_input = EDID_VIDEO_INPUT(data);
     531           0 :         edid->edid_max_hsize = EDID_MAX_HSIZE(data);
     532           0 :         edid->edid_max_vsize = EDID_MAX_VSIZE(data);
     533             : 
     534           0 :         edid->edid_gamma = EDID_GAMMA(data);
     535           0 :         edid->edid_features = EDID_FEATURES(data);
     536             : 
     537           0 :         edid->edid_chroma.ec_redx = EDID_CHROMA_REDX(data);
     538           0 :         edid->edid_chroma.ec_redy = EDID_CHROMA_REDX(data);
     539           0 :         edid->edid_chroma.ec_greenx = EDID_CHROMA_GREENX(data);
     540           0 :         edid->edid_chroma.ec_greeny = EDID_CHROMA_GREENY(data);
     541           0 :         edid->edid_chroma.ec_bluex = EDID_CHROMA_BLUEX(data);
     542           0 :         edid->edid_chroma.ec_bluey = EDID_CHROMA_BLUEY(data);
     543           0 :         edid->edid_chroma.ec_whitex = EDID_CHROMA_WHITEX(data);
     544           0 :         edid->edid_chroma.ec_whitey = EDID_CHROMA_WHITEY(data);
     545             : 
     546             :         /* lookup established modes */
     547           0 :         edid->edid_nmodes = 0;
     548           0 :         edid->edid_preferred_mode = NULL;
     549           0 :         estmodes = EDID_EST_TIMING(data);
     550           0 :         for (i = 0; i < 16; i++) {
     551           0 :                 if (estmodes & (1 << i)) {
     552           0 :                         vmp = edid_mode_lookup_list(_edid_modes[i]);
     553           0 :                         if (vmp != NULL) {
     554           0 :                                 edid->edid_modes[edid->edid_nmodes] = *vmp;
     555           0 :                                 edid->edid_nmodes++;
     556           0 :                         }
     557             : #ifdef DIAGNOSTIC
     558             :                           else
     559           0 :                                 printf("no data for est. mode %s\n",
     560           0 :                                     _edid_modes[i]);
     561             : #endif
     562             :                 }
     563             :         }
     564             : 
     565             :         /* do standard timing section */
     566           0 :         for (i = 0; i < EDID_STD_TIMING_COUNT; i++) {
     567           0 :                 struct videomode        mode;
     568           0 :                 if (edid_std_timing(data + EDID_OFFSET_STD_TIMING + i * 2,
     569             :                         &mode)) {
     570           0 :                         edid->edid_modes[edid->edid_nmodes] = mode;
     571           0 :                         edid->edid_nmodes++;
     572           0 :                 }
     573           0 :         }
     574             :         /* do detailed timings and descriptors */
     575           0 :         for (i = 0; i < EDID_BLOCK_COUNT; i++) {
     576           0 :                 edid_block(edid, data + EDID_OFFSET_DESC_BLOCK +
     577           0 :                     i * EDID_BLOCK_SIZE);
     578             :         }
     579             : 
     580           0 :         edid_strchomp(edid->edid_vendorname);
     581           0 :         edid_strchomp(edid->edid_productname);
     582           0 :         edid_strchomp(edid->edid_serial);
     583           0 :         edid_strchomp(edid->edid_comment);
     584             : 
     585             :         /*
     586             :          * XXX
     587             :          * some monitors lie about their maximum supported dot clock
     588             :          * by claiming to support modes which need a higher dot clock
     589             :          * than the stated maximum.
     590             :          * For sanity's sake we bump it to the highest dot clock we find
     591             :          * in the list of supported modes
     592             :          */
     593           0 :         for (i = 0; i < edid->edid_nmodes; i++)
     594           0 :                 if (edid->edid_modes[i].dot_clock > max_dotclock)
     595           0 :                         max_dotclock = edid->edid_modes[i].dot_clock;
     596             : 
     597           0 :         printf("max_dotclock according to supported modes: %d\n",
     598             :             max_dotclock);
     599             : 
     600           0 :         mhz = (max_dotclock + 999) / 1000;
     601             : 
     602           0 :         if (edid->edid_have_range) {
     603             : 
     604           0 :                 if (mhz > edid->edid_range.er_max_clock)
     605           0 :                         edid->edid_range.er_max_clock = mhz;
     606             :         } else
     607           0 :                 edid->edid_range.er_max_clock = mhz;
     608             : 
     609           0 :         return 0;
     610           0 : }
     611             : 

Generated by: LCOV version 1.13