[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