diff options
Diffstat (limited to 'libgamma_internal_parse_edid.c')
-rw-r--r-- | libgamma_internal_parse_edid.c | 90 |
1 files changed, 61 insertions, 29 deletions
diff --git a/libgamma_internal_parse_edid.c b/libgamma_internal_parse_edid.c index aa1b87c..32641c1 100644 --- a/libgamma_internal_parse_edid.c +++ b/libgamma_internal_parse_edid.c @@ -7,6 +7,9 @@ * http://en.wikipedia.org/w/index.php?title=Extended_display_identification_data&oldid=46295569 * * EDID structure revision 1.3: + * https://en.wikipedia.org/w/index.php?title=Extended_Display_Identification_Data&oldid=805561402#EDID_1.3_data_format + * + * EDID structure revision 1.4: * http://en.wikipedia.org/wiki/Extended_display_identification_data */ @@ -21,47 +24,54 @@ * @return Non-zero on error */ int -libgamma_internal_parse_edid(libgamma_crtc_information_t *restrict this, int32_t fields) +libgamma_internal_parse_edid(libgamma_crtc_information_t *restrict this, unsigned long long fields) { #define __test_version(edid, major, minor_min, minor_max)\ ((edid)[18] == (major) && (minor_min) <= (edid)[19] && (edid)[19] <= (minor_max)) #define __m(value)\ (this->edid[index++] != (value)) + uint16_t red_x, green_x, blue_x, white_x; + uint16_t red_y, green_y, blue_y, white_y; int error = 0, checksum = 0; size_t i, index = 0; - /* If the length of the EDID is not 128 bytes, we know that it is not of EDID - structure revision 1.0–1.3, and thus we do not support it. Additionally - this make sure we do not do segmentation violation on the next test. */ - if (this->edid_length != 128) + /* If the length of the EDID is less than 128 bytes, we know that it is + * not of EDID structure revision 1.0–1.4, and thus we do not support it; + * however, extensions allows it to be longer tha 128 bytes */ + if (this->edid_length < 128) error = LIBGAMMA_EDID_LENGTH_UNSUPPORTED; - /* Check that the magic number of that of the EDID structure. */ + /* Check that the magic number of that of the EDID structure */ else if (__m(0x00) || __m(0xFF) || __m(0xFF) || __m(0xFF) || __m(0xFF) || __m(0xFF) || __m(0xFF) || __m(0x00)) error = LIBGAMMA_EDID_WRONG_MAGIC_NUMBER; - /* Check that EDID structure revision 1.1–1.3 is used, those are the only - version we support. EDID structure revision 1.3 is also by far the most - commonly use revision and it is currently the newest revision. We know - that parsing works for both revision 1.1 and revision 1.3, because of - this we assume it is also correct for revision 1.2. However, we are not - assuming this for revision 1.0 which appeared in August 1994 and was - replaced by revision 1.1 in April 1996. */ - else if (!__test_version(this->edid, 1, 1, 3)) + /* Check that EDID structure revision 1.1–1.4 is used, those are the only + * version we support. EDID structure revisions 1.3 and 1.4 is also by far + * the most commonly use revision and it is currently the newest revisions. + * We know that parsing works for revisions 1.1, 1.3, and 1.4, because of + * this we assume it is also correct for revision 1.2. However, we are not + * assuming this for revision 1.0 which appeared in August 1994 and was + * replaced by revision 1.1 in April 1996. */ + else if (!__test_version(this->edid, 1, 1, 4)) error = LIBGAMMA_EDID_REVISION_UNSUPPORTED; /* If we have encountered an error, report it for the fields that require - the EDID to be parsed. Note that it is not stored for the EDID field - itself because it is not considered an error just because we do not - support the used version. */ + * the EDID to be parsed. Note that it is not stored for the EDID field + * itself because it is not considered an error just because we do not + * support the used version. */ this->width_mm_edid_error = this->height_mm_edid_error = this->gamma_error = error; + this->chroma_error = this->white_point_error = error; + + /* Set errors and exit if we have error, especially important if this->edid_length < 128 */ + if (error) + goto out; /* Retrieve the size of the viewport. This is done even if it is not - requested because it is not worth it branch. */ + * requested because it is not worth it to branch. */ this->width_mm_edid = (size_t)this->edid[21] * 10; this->height_mm_edid = (size_t)this->edid[22] * 10; - /* Retrieve the monitor's gamma characteristics. */ - if ((fields & LIBGAMMA_CRTC_INFO_GAMMA) && !error) { + /* Retrieve the monitor's gamma characteristics */ + if (fields & LIBGAMMA_CRTC_INFO_GAMMA) { if (this->edid[23] == 0xFF) { /* If the gamma charactistics is FFh (3,55) it should be interpreted as not specified. */ this->gamma_error = LIBGAMMA_GAMMA_NOT_SPECIFIED; @@ -71,27 +81,49 @@ libgamma_internal_parse_edid(libgamma_crtc_information_t *restrict this, int32_t } } - /* If not error has occurred, calculate and test the checksum. - It is not considered an error that the gamma characteristics - is left unspecified in the EDID. */ + /* Retrieve the monitor's subpixel chromas */ + if (fields & (LIBGAMMA_CRTC_INFO_CHROMA | LIBGAMMA_CRTC_INFO_WHITE_POINT)) { + red_x = (((uint16_t)this->edid[25] >> 6) & 2) | ((uint16_t)this->edid[27] << 2); + red_y = (((uint16_t)this->edid[25] >> 4) & 2) | ((uint16_t)this->edid[28] << 2); + green_x = (((uint16_t)this->edid[25] >> 2) & 2) | ((uint16_t)this->edid[29] << 2); + green_y = (((uint16_t)this->edid[25] >> 0) & 2) | ((uint16_t)this->edid[30] << 2); + blue_x = (((uint16_t)this->edid[26] >> 6) & 2) | ((uint16_t)this->edid[31] << 2); + blue_y = (((uint16_t)this->edid[26] >> 4) & 2) | ((uint16_t)this->edid[32] << 2); + white_x = (((uint16_t)this->edid[26] >> 2) & 2) | ((uint16_t)this->edid[33] << 2); + white_y = (((uint16_t)this->edid[26] >> 6) & 2) | ((uint16_t)this->edid[34] << 2); + /* Even though the maximum value as encoded is 1023, the values should be divided by 1024 */ + this->red_chroma_x = (float)red_x / 1024.f; + this->red_chroma_y = (float)red_y / 1024.f; + this->green_chroma_x = (float)green_x / 1024.f; + this->green_chroma_y = (float)green_y / 1024.f; + this->blue_chroma_x = (float)blue_x / 1024.f; + this->blue_chroma_y = (float)blue_y / 1024.f; + this->white_point_x = (float)white_x / 1024.f; + this->white_point_y = (float)white_y / 1024.f; + } + + /* Calculate and test the checksum. It is not considered + * an error that the gamma characteristics is left + * unspecified in the EDID. */ if (!error) - for (i = 0; i < this->edid_length; i++) + for (i = 0; i < 128; i++) checksum += (int)this->edid[i]; - /* The checksum should be zero. */ + /* The checksum should be zero */ if (checksum & 255) { /* Store the error in all fields that require the EDID to be parsed, - as well as the EDID field itself. */ + * as well as the EDID field itself */ error = LIBGAMMA_EDID_CHECKSUM_ERROR; + out: this->edid_error = this->width_mm_edid_error = this->height_mm_edid_error = error; /* If the gamma characteristics is not specified, that is kept, - and the checksum error is augmented. */ + * and the checksum error is augmented. */ this->gamma_error = this->gamma_error == LIBGAMMA_GAMMA_NOT_SPECIFIED ? LIBGAMMA_GAMMA_NOT_SPECIFIED_AND_EDID_CHECKSUM_ERROR : error; } /* Return whether or not we encountered an error or if - the gamma characteristics was requested but is not - specified in the monitor's EDID. */ + * the gamma characteristics was requested but is not + * specified in the monitor's EDID */ return error | this->gamma_error; #undef __m |