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 24 extern 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. 33 static status_t 34 verify_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 60 static status_t 61 ddc2_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 96 static status_t 97 ddc2_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 137 void 138 ddc2_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 152 status_t 153 ddc2_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