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