[PATCH 2/2] Move the EDID parsing to its own file

Richard Hughes hughsient at gmail.com
Thu May 2 14:33:36 PDT 2013


---
 src/Makefile.am      |   2 +
 src/compositor-drm.c | 180 +--------------------------------------------------
 src/compositor.c     |  21 ++++++
 src/compositor.h     |   5 ++
 src/edid.c           | 175 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/edid.h           |  48 ++++++++++++++
 6 files changed, 254 insertions(+), 177 deletions(-)
 create mode 100644 src/edid.c
 create mode 100644 src/edid.h

diff --git a/src/Makefile.am b/src/Makefile.am
index d33ebc5..1e8965c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,6 +18,8 @@ weston_SOURCES =				\
 	log.c					\
 	compositor.c				\
 	compositor.h				\
+	edid.c					\
+	edid.h					\
 	filter.c				\
 	filter.h				\
 	screenshooter.c				\
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index e4a1919..c507e72 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -29,7 +29,6 @@
 
 #include <errno.h>
 #include <stdlib.h>
-#include <ctype.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -136,24 +135,6 @@ struct drm_fb {
 	void *map;
 };
 
-struct drm_color_Yxy {
-	double Y;
-	double x;
-	double y;
-};
-
-struct drm_edid {
-	char eisa_id[13];
-	char monitor_name[13];
-	char pnp_id[5];
-	char serial_number[13];
-	struct drm_color_Yxy whitepoint;
-	struct drm_color_Yxy primary_red;
-	struct drm_color_Yxy primary_green;
-	struct drm_color_Yxy primary_blue;
-	double gamma;
-};
-
 struct drm_output {
 	struct weston_output   base;
 
@@ -161,7 +142,6 @@ struct drm_output {
 	int pipe;
 	uint32_t connector_id;
 	drmModeCrtcPtr original_crtc;
-	struct drm_edid edid;
 
 	int vblank_pending;
 	int page_flip_pending;
@@ -1529,146 +1509,6 @@ drm_output_fini_pixman(struct drm_output *output)
 }
 
 static void
-edid_parse_string(const uint8_t *data, char text[])
-{
-	int i;
-	int replaced = 0;
-
-	/* this is always 12 bytes, but we can't guarantee it's null
-	 * terminated or not junk. */
-	strncpy(text, (const char *) data, 12);
-
-	/* remove insane chars */
-	for (i = 0; text[i] != '\0'; i++) {
-		if (text[i] == '\n' ||
-		    text[i] == '\r') {
-			text[i] = '\0';
-			break;
-		}
-	}
-
-	/* ensure string is printable */
-	for (i = 0; text[i] != '\0'; i++) {
-		if (!isprint(text[i])) {
-			text[i] = '-';
-			replaced++;
-		}
-	}
-
-	/* if the string is random junk, ignore the string */
-	if (replaced > 4)
-		text[0] = '\0';
-}
-
-#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING	0xfe
-#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME		0xfc
-#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER	0xff
-#define EDID_OFFSET_DATA_BLOCKS				0x36
-#define EDID_OFFSET_LAST_BLOCK				0x6c
-#define EDID_OFFSET_PNPID				0x08
-#define EDID_OFFSET_SERIAL				0x0c
-
-static int
-edid_get_bit(int in, int bit)
-{
-	return (in & (1 << bit)) >> bit;
-}
-
-static int
-edid_get_bits(int in, int begin, int end)
-{
-	int mask = (1 << (end - begin + 1)) - 1;
-	return (in >> begin) & mask;
-}
-
-static double
-edid_decode_fraction(int high, int low)
-{
-	double result = 0.0;
-	int i;
-
-	high = (high << 2) | low;
-	for (i = 0; i < 10; ++i)
-		result += edid_get_bit(high, i) * pow(2, i - 10);
-	return result;
-}
-
-static int
-edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
-{
-	int i;
-	uint32_t serial_number;
-
-	/* check header */
-	if (length < 128)
-		return -1;
-	if (data[0] != 0x00 || data[1] != 0xff)
-		return -1;
-
-	/* decode the PNP ID from three 5 bit words packed into 2 bytes
-	 * /--08--\/--09--\
-	 * 7654321076543210
-	 * |\---/\---/\---/
-	 * R  C1   C2   C3 */
-	edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
-	edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
-	edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
-	edid->pnp_id[3] = '\0';
-
-	/* get native gamma */
-	if (data[0x17] == 0xff)
-		edid->gamma = -1.0;
-	else
-		edid->gamma = (data[0x17] + 100.0) / 100.0;
-
-	/* get primaries and whitepoint */
-	edid->primary_red.Y = 1.0f;
-	edid->primary_red.x = edid_decode_fraction(data[0x1b], edid_get_bits(data[0x19], 6, 7));
-	edid->primary_red.y = edid_decode_fraction(data[0x1c], edid_get_bits(data[0x19], 5, 4));
-	edid->primary_green.Y = 1.0f;
-	edid->primary_green.x = edid_decode_fraction(data[0x1d], edid_get_bits(data[0x19], 2, 3));
-	edid->primary_green.y = edid_decode_fraction(data[0x1e], edid_get_bits(data[0x19], 0, 1));
-	edid->primary_blue.Y = 1.0f;
-	edid->primary_blue.x = edid_decode_fraction(data[0x1f], edid_get_bits(data[0x1a], 6, 7));
-	edid->primary_blue.y = edid_decode_fraction(data[0x20], edid_get_bits(data[0x1a], 4, 5));
-	edid->whitepoint.Y = 1.0f;
-	edid->whitepoint.x = edid_decode_fraction(data[0x21], edid_get_bits(data[0x1a], 2, 3));
-	edid->whitepoint.y = edid_decode_fraction(data[0x22], edid_get_bits(data[0x1a], 0, 1));
-
-	/* maybe there isn't a ASCII serial number descriptor, so use this instead */
-	serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
-	serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
-	serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
-	serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
-	if (serial_number > 0)
-		sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
-
-	/* parse EDID data */
-	for (i = EDID_OFFSET_DATA_BLOCKS;
-	     i <= EDID_OFFSET_LAST_BLOCK;
-	     i += 18) {
-		/* ignore pixel clock data */
-		if (data[i] != 0)
-			continue;
-		if (data[i+2] != 0)
-			continue;
-
-		/* any useful blocks? */
-		if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
-			edid_parse_string(&data[i+5],
-					  edid->monitor_name);
-		} else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
-			edid_parse_string(&data[i+5],
-					  edid->serial_number);
-		} else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
-			edid_parse_string(&data[i+5],
-					  edid->eisa_id);
-		}
-	}
-	return 0;
-}
-
-static void
 find_and_parse_output_edid(struct drm_compositor *ec,
 			   struct drm_output *output,
 			   drmModeConnector *connector)
@@ -1676,7 +1516,6 @@ find_and_parse_output_edid(struct drm_compositor *ec,
 	drmModePropertyBlobPtr edid_blob = NULL;
 	drmModePropertyPtr property;
 	int i;
-	int rc;
 
 	for (i = 0; i < connector->count_props && !edid_blob; i++) {
 		property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
@@ -1691,22 +1530,9 @@ find_and_parse_output_edid(struct drm_compositor *ec,
 	}
 	if (!edid_blob)
 		return;
-
-	rc = edid_parse(&output->edid,
-			edid_blob->data,
-			edid_blob->length);
-	if (!rc) {
-		weston_log("EDID data '%s', '%s', '%s'\n",
-			   output->edid.pnp_id,
-			   output->edid.monitor_name,
-			   output->edid.serial_number);
-		if (output->edid.pnp_id[0] != '\0')
-			output->base.make = output->edid.pnp_id;
-		if (output->edid.monitor_name[0] != '\0')
-			output->base.model = output->edid.monitor_name;
-		if (output->edid.serial_number[0] != '\0')
-			output->base.serial_number = output->edid.serial_number;
-	}
+	weston_output_set_edid(&output->base,
+			       edid_blob->data,
+			       edid_blob->length);
 	drmModeFreePropertyBlob(edid_blob);
 }
 
diff --git a/src/compositor.c b/src/compositor.c
index a6610e6..21caa7e 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2975,6 +2975,27 @@ weston_output_compute_transform(struct weston_output *output)
 }
 
 WL_EXPORT void
+weston_output_set_edid(struct weston_output *output,
+		       const uint8_t *data, size_t length)
+{
+	int rc;
+
+	rc = weston_edid_parse(&output->edid, data, length);
+	if (!rc) {
+		weston_log("EDID data '%s', '%s', '%s'\n",
+			   output->edid.pnp_id,
+			   output->edid.monitor_name,
+			   output->edid.serial_number);
+		if (output->edid.pnp_id[0] != '\0')
+			output->make = output->edid.pnp_id;
+		if (output->edid.monitor_name[0] != '\0')
+			output->model = output->edid.monitor_name;
+		if (output->edid.serial_number[0] != '\0')
+			output->serial_number = output->edid.serial_number;
+	}
+}
+
+WL_EXPORT void
 weston_output_update_matrix(struct weston_output *output)
 {
 	float magnification;
diff --git a/src/compositor.h b/src/compositor.h
index 7da6c48..6f15350 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -34,6 +34,7 @@ extern "C" {
 
 #include "version.h"
 #include "matrix.h"
+#include "edid.h"
 #include "config-parser.h"
 
 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
@@ -181,6 +182,7 @@ struct weston_output {
 	int disable_planes;
 
 	char *make, *model, *serial_number;
+	struct weston_edid_info edid;
 	uint32_t subpixel;
 	uint32_t transform;
 	
@@ -766,6 +768,9 @@ weston_output_update_zoom(struct weston_output *output, uint32_t type);
 void
 weston_output_update_matrix(struct weston_output *output);
 void
+weston_output_set_edid(struct weston_output *output,
+		       const uint8_t *data, size_t length);
+void
 weston_output_move(struct weston_output *output, int x, int y);
 void
 weston_output_init(struct weston_output *output, struct weston_compositor *c,
diff --git a/src/edid.c b/src/edid.c
new file mode 100644
index 0000000..f591e74
--- /dev/null
+++ b/src/edid.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright © 2013 Richard Hughes
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "edid.h"
+
+static void
+weston_edid_parse_string(const uint8_t *data, char text[])
+{
+	int i;
+	int replaced = 0;
+
+	/* this is always 12 bytes, but we can't guarantee it's null
+	 * terminated or not junk. */
+	strncpy(text, (const char *) data, 12);
+
+	/* remove insane chars */
+	for (i = 0; text[i] != '\0'; i++) {
+		if (text[i] == '\n' ||
+		    text[i] == '\r') {
+			text[i] = '\0';
+			break;
+		}
+	}
+
+	/* ensure string is printable */
+	for (i = 0; text[i] != '\0'; i++) {
+		if (!isprint(text[i])) {
+			text[i] = '-';
+			replaced++;
+		}
+	}
+
+	/* if the string is random junk, ignore the string */
+	if (replaced > 4)
+		text[0] = '\0';
+}
+
+#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING	0xfe
+#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME		0xfc
+#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER	0xff
+#define EDID_OFFSET_DATA_BLOCKS				0x36
+#define EDID_OFFSET_LAST_BLOCK				0x6c
+#define EDID_OFFSET_PNPID				0x08
+#define EDID_OFFSET_SERIAL				0x0c
+
+static int
+edid_get_bit(int in, int bit)
+{
+	return (in & (1 << bit)) >> bit;
+}
+
+static int
+edid_get_bits(int in, int begin, int end)
+{
+	int mask = (1 << (end - begin + 1)) - 1;
+	return (in >> begin) & mask;
+}
+
+static double
+edid_decode_fraction(int high, int low)
+{
+	double result = 0.0;
+	int i;
+
+	high = (high << 2) | low;
+	for (i = 0; i < 10; ++i)
+		result += edid_get_bit(high, i) * pow(2, i - 10);
+	return result;
+}
+
+int
+weston_edid_parse(struct weston_edid_info *edid,
+		  const uint8_t *data, size_t length)
+{
+	int i;
+	uint32_t serial_number;
+
+	/* check header */
+	if (length < 128)
+		return -1;
+	if (data[0] != 0x00 || data[1] != 0xff)
+		return -1;
+
+	/* decode the PNP ID from three 5 bit words packed into 2 bytes
+	 * /--08--\/--09--\
+	 * 7654321076543210
+	 * |\---/\---/\---/
+	 * R  C1   C2   C3 */
+	edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
+	edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
+	edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
+	edid->pnp_id[3] = '\0';
+
+	/* get native gamma */
+	if (data[0x17] == 0xff)
+		edid->gamma = -1.0;
+	else
+		edid->gamma = (data[0x17] + 100.0) / 100.0;
+
+	/* get primaries and whitepoint */
+	edid->primary_red.Y = 1.0f;
+	edid->primary_red.x = edid_decode_fraction(data[0x1b], edid_get_bits(data[0x19], 6, 7));
+	edid->primary_red.y = edid_decode_fraction(data[0x1c], edid_get_bits(data[0x19], 5, 4));
+	edid->primary_green.Y = 1.0f;
+	edid->primary_green.x = edid_decode_fraction(data[0x1d], edid_get_bits(data[0x19], 2, 3));
+	edid->primary_green.y = edid_decode_fraction(data[0x1e], edid_get_bits(data[0x19], 0, 1));
+	edid->primary_blue.Y = 1.0f;
+	edid->primary_blue.x = edid_decode_fraction(data[0x1f], edid_get_bits(data[0x1a], 6, 7));
+	edid->primary_blue.y = edid_decode_fraction(data[0x20], edid_get_bits(data[0x1a], 4, 5));
+	edid->whitepoint.Y = 1.0f;
+	edid->whitepoint.x = edid_decode_fraction(data[0x21], edid_get_bits(data[0x1a], 2, 3));
+	edid->whitepoint.y = edid_decode_fraction(data[0x22], edid_get_bits(data[0x1a], 0, 1));
+
+	/* maybe there isn't a ASCII serial number descriptor, so use this instead */
+	serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
+	serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
+	serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
+	serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
+	if (serial_number > 0)
+		sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
+
+	/* parse EDID data */
+	for (i = EDID_OFFSET_DATA_BLOCKS;
+	     i <= EDID_OFFSET_LAST_BLOCK;
+	     i += 18) {
+		/* ignore pixel clock data */
+		if (data[i] != 0)
+			continue;
+		if (data[i+2] != 0)
+			continue;
+
+		/* any useful blocks? */
+		if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
+			weston_edid_parse_string(&data[i+5],
+					  edid->monitor_name);
+		} else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
+			weston_edid_parse_string(&data[i+5],
+					  edid->serial_number);
+		} else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
+			weston_edid_parse_string(&data[i+5],
+					  edid->eisa_id);
+		}
+	}
+	return 0;
+}
diff --git a/src/edid.h b/src/edid.h
new file mode 100644
index 0000000..f5f7603
--- /dev/null
+++ b/src/edid.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2013 Richard Hughes
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WESTON_EDID_H_
+#define _WESTON_EDID_H_
+
+struct weston_edid_color_Yxy {
+	double Y;
+	double x;
+	double y;
+};
+
+struct weston_edid_info {
+	char eisa_id[13];
+	char monitor_name[13];
+	char pnp_id[5];
+	char serial_number[13];
+	struct weston_edid_color_Yxy whitepoint;
+	struct weston_edid_color_Yxy primary_red;
+	struct weston_edid_color_Yxy primary_green;
+	struct weston_edid_color_Yxy primary_blue;
+	double gamma;
+};
+
+int
+weston_edid_parse(struct weston_edid_info *edid,
+		  const uint8_t *data, size_t length);
+
+#endif
-- 
1.8.2.1



More information about the wayland-devel mailing list