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 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 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 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 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 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