ddc.c revision c54a6536d67c85b7d54ee153ac984200bdbf727f
1/*
2 * Copyright 2003, Thomas Kurschel. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6/*!	DDC communication */
7
8
9#include "ddc_int.h"
10#include "ddc.h"
11#include "i2c.h"
12
13#include <KernelExport.h>
14#include <OS.h>
15
16#include <stdlib.h>
17
18
19#define READ_RETRIES 4		// number of retries to read ddc data
20
21
22#define TRACE_DDC
23#ifdef TRACE_DDC
24extern void _sPrintf(const char* format, ...);
25#	define TRACE(x...) _sPrintf("DDC: " x)
26#else
27#	define TRACE(x...) ;
28#endif
29
30
31
32//! Verify checksum of DDC data.
33static status_t
34verify_checksum(const uint8 *data, size_t len)
35{
36	uint32 index;
37	uint8 sum = 0;
38	uint8 allOr = 0;
39
40	for (index = 0; index < len; ++index, ++data) {
41		sum += *data;
42		allOr |= *data;
43	}
44
45	if (allOr == 0) {
46		TRACE("verify_checksum() DDC information contains zeros only\n");
47		return B_ERROR;
48	}
49
50	if (sum != 0) {
51		TRACE("verify_checksum() Checksum error in DDC information\n");
52		return B_IO_ERROR;
53	}
54
55	return B_OK;
56}
57
58
59//!	Read ddc2 data from monitor
60static status_t
61ddc2_read(const i2c_bus *bus, int start, uint8 *buffer, size_t length)
62{
63	status_t status = B_OK;
64	uint8 writeBuffer[2];
65	int i;
66
67	writeBuffer[0] = start & 0xff;
68	writeBuffer[1] = (start >> 8) & 0xff;
69
70	for (i = 0; i < READ_RETRIES; ++i) {
71		status = i2c_send_receive(bus, 0xa0, writeBuffer,
72			start < 0x100 ? 1 : 2, buffer, length);
73
74		if (status != B_OK)
75			TRACE("ddc2_read(): DDC information read failure\n");
76
77		if (status == B_OK) {
78			status = verify_checksum(buffer, length);
79			if (status == B_OK)
80				break;
81
82			dprintf("DDC checksum incorrect!\n");
83		}
84	}
85
86	return status;
87}
88
89
90/*!
91	Reading VDIF has not been tested.
92	it seems that almost noone supports VDIF which makes testing hard,
93	but what's the point anyway?
94*/
95#if 0
96static status_t
97ddc2_read_vdif(const i2c_bus *bus, int start,
98	void **vdif, size_t *vdif_len)
99{
100	status_t res;
101	uint8 *data, *cur_data;
102	int i;
103	uint8 buffer[64];
104
105	*vdif = NULL;
106	*vdif_len = 0;
107
108	res = ddc2_read(bus, start, buffer, 64);
109	SHOW_INFO(2, "%x", buffer[0]);
110	if (res != B_OK || buffer[0] == 0)
111		return B_OK;
112
113	// each block is 63 bytes plus 1 checksum long
114	// we strip the checksum but store data directly into
115	// buffer, so we need an extra byte for checksum of the last block
116	data = malloc(buffer[0] * 63 + 1);
117	if (data == NULL)
118		return B_NO_MEMORY;
119
120	cur_data = data;
121	for (i = 0; i < buffer[0]; ++i) {
122		ddc2_read(bus, start + i * 64, cur_data, 64);
123		// strip checksum byte
124		cur_data += 63;
125	}
126
127	*vdif_len = buffer[0] * 63;
128	*vdif = data;
129	return B_OK;
130}
131#endif
132
133
134//	#pragma mark -
135
136
137void
138ddc2_init_timing(i2c_bus *bus)
139{
140	i2c_get100k_timing(&bus->timing);
141
142	// VESA standard
143	bus->timing.start_timeout = 550;
144	bus->timing.byte_timeout = 2200;
145	bus->timing.bit_timeout = 40;
146	bus->timing.ack_start_timeout = 40;
147	bus->timing.ack_timeout = 40;
148}
149
150
151//! Read EDID and VDIF from monitor via ddc2
152status_t
153ddc2_read_edid1(const i2c_bus *bus, edid1_info *edid,
154	void **vdif, size_t *vdifLength)
155{
156	edid1_raw raw;
157	status_t status = ddc2_read(bus, 0, (uint8 *)&raw, sizeof(raw));
158	if (status != B_OK)
159		return status;
160
161	if (raw.version.version != 1 || raw.version.revision > 4) {
162		TRACE("ddc2_read_edid1() EDID version or revision out of range\n");
163		return B_ERROR;
164	}
165
166	edid_decode(edid, &raw);
167
168	if (vdif != NULL)
169		*vdif = NULL;
170	if (vdifLength != NULL)
171		*vdifLength = 0;
172
173	// skip vdif as long as it's not tested
174#if 0
175	status = ddc2_read_vdif(bus, sizeof(raw) * (edid->num_sections + 1),
176		vdif, vdifLength);
177	if (status != B_OK)
178		return status;
179#endif
180
181	return B_OK;
182}
183