vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / common / ddc.c
blob8b1210c75af61c6c84a32a7be6660b0256773a54
1 /*
2 * Copyright 2003, Thomas Kurschel. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
6 /*! DDC communication */
9 #include "ddc_int.h"
10 #include "ddc.h"
11 #include "i2c.h"
13 #include <KernelExport.h>
14 #include <OS.h>
16 #include <stdlib.h>
19 #define READ_RETRIES 4 // number of retries to read ddc data
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
30 //! Verify checksum of DDC data.
31 static status_t
32 verify_checksum(const uint8 *data, size_t len)
34 uint32 index;
35 uint8 sum = 0;
36 uint8 allOr = 0;
38 for (index = 0; index < len; ++index, ++data) {
39 sum += *data;
40 allOr |= *data;
43 if (allOr == 0) {
44 TRACE("%s: DDC information contains zeros only\n", __func__);
45 return B_ERROR;
48 if (sum != 0) {
49 TRACE("%s: Checksum error in DDC information\n", __func__);
50 return B_IO_ERROR;
53 return B_OK;
57 //! Read ddc2 data from monitor
58 static status_t
59 ddc2_read(const i2c_bus *bus, int start, uint8 *buffer, size_t length)
61 status_t status = B_OK;
62 uint8 writeBuffer[2];
63 int i;
65 writeBuffer[0] = start & 0xff;
66 writeBuffer[1] = (start >> 8) & 0xff;
68 for (i = 0; i < READ_RETRIES; ++i) {
69 status = i2c_send_receive(bus, 0xa0, writeBuffer,
70 start < 0x100 ? 1 : 2, buffer, length);
72 if (status != B_OK)
73 TRACE("%s: DDC information read failure\n", __func__);
75 if (status == B_OK) {
76 status = verify_checksum(buffer, length);
77 if (status == B_OK)
78 break;
80 dprintf("%s: DDC checksum incorrect!\n", __func__);
84 return status;
88 /*!
89 Reading VDIF has not been tested.
90 it seems that almost noone supports VDIF which makes testing hard,
91 but what's the point anyway?
93 #if 0
94 static status_t
95 ddc2_read_vdif(const i2c_bus *bus, int start,
96 void **vdif, size_t *vdif_len)
98 status_t res;
99 uint8 *data, *cur_data;
100 int i;
101 uint8 buffer[64];
103 *vdif = NULL;
104 *vdif_len = 0;
106 res = ddc2_read(bus, start, buffer, 64);
107 SHOW_INFO(2, "%x", buffer[0]);
108 if (res != B_OK || buffer[0] == 0)
109 return B_OK;
111 // each block is 63 bytes plus 1 checksum long
112 // we strip the checksum but store data directly into
113 // buffer, so we need an extra byte for checksum of the last block
114 data = malloc(buffer[0] * 63 + 1);
115 if (data == NULL)
116 return B_NO_MEMORY;
118 cur_data = data;
119 for (i = 0; i < buffer[0]; ++i) {
120 ddc2_read(bus, start + i * 64, cur_data, 64);
121 // strip checksum byte
122 cur_data += 63;
125 *vdif_len = buffer[0] * 63;
126 *vdif = data;
127 return B_OK;
129 #endif
132 // #pragma mark -
135 void
136 ddc2_init_timing(i2c_bus *bus)
138 i2c_get100k_timing(&bus->timing);
140 // VESA standard
141 bus->timing.start_timeout = 550;
142 bus->timing.byte_timeout = 2200;
143 bus->timing.bit_timeout = 40;
144 bus->timing.ack_start_timeout = 40;
145 bus->timing.ack_timeout = 40;
149 //! Read EDID and VDIF from monitor via ddc2
150 status_t
151 ddc2_read_edid1(const i2c_bus *bus, edid1_info *edid,
152 void **vdif, size_t *vdifLength)
154 edid1_raw raw;
155 status_t status = ddc2_read(bus, 0, (uint8 *)&raw, sizeof(raw));
156 if (status != B_OK)
157 return status;
159 if (raw.version.version != 1 || raw.version.revision > 4) {
160 TRACE("%s: EDID version or revision out of range\n", __func__);
161 return B_ERROR;
164 edid_decode(edid, &raw);
166 if (vdif != NULL)
167 *vdif = NULL;
168 if (vdifLength != NULL)
169 *vdifLength = 0;
171 // skip vdif as long as it's not tested
172 #if 0
173 status = ddc2_read_vdif(bus, sizeof(raw) * (edid->num_sections + 1),
174 vdif, vdifLength);
175 if (status != B_OK)
176 return status;
177 #endif
179 return B_OK;