The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/videomode/edid.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3003529f7f4cf0195497a9edfcb0cd65


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.