1 /* 2 * Copyright (c) 2003, Thomas Kurschel. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /*! 7 Part of DDC driver 8 9 EDID decoder. 10 11 The EDID information is tightly packed; this file takes care of 12 converting it to a usable structure. 13 */ 14 15 16 #include "edid.h" 17 18 #include <KernelExport.h> 19 #include <string.h> 20 21 22 // 23 // from hereon a bunch of decoders follow for each EDID section 24 // 25 26 static void 27 decode_vendor(edid1_vendor *vendor, const edid1_vendor_raw *raw) 28 { 29 vendor->manufacturer[0] = raw->c1 + '@'; 30 vendor->manufacturer[1] = ((raw->c2_high << 3) | raw->c2_low) + '@'; 31 vendor->manufacturer[2] = raw->c3 + '@'; 32 vendor->manufacturer[3] = 0; 33 vendor->prod_id = B_LENDIAN_TO_HOST_INT16(raw->prod_id); 34 vendor->serial = B_LENDIAN_TO_HOST_INT32(raw->serial); 35 vendor->week = raw->week; 36 vendor->year = raw->year + 1990; 37 } 38 39 40 static void 41 decode_version(edid1_version *version, const edid1_version_raw *raw) 42 { 43 version->version = raw->version; 44 version->revision = raw->revision; 45 } 46 47 48 static void 49 decode_display(edid1_display *display, const edid1_display_raw *raw) 50 { 51 display->input_type = raw->input_type; 52 display->input_voltage = raw->input_voltage; 53 display->setup = raw->setup; 54 display->sep_sync = raw->sep_sync; 55 display->comp_sync = raw->comp_sync; 56 display->sync_on_green = raw->sync_on_green; 57 display->sync_serr = raw->sync_serr; 58 59 display->h_size = raw->h_size; 60 display->v_size = raw->v_size; 61 display->gamma = raw->gamma; 62 63 display->dpms_standby = raw->dpms_standby; 64 display->dpms_suspend = raw->dpms_suspend; 65 display->dpms_off = raw->dpms_off; 66 display->display_type = raw->display_type; 67 display->std_colour_space = raw->std_colour_space; 68 display->preferred_timing_mode = raw->preferred_timing_mode; 69 display->gtf_supported = raw->gtf_supported; 70 71 display->red_x = ((uint16)raw->red_x << 2) | raw->red_x_low; 72 display->red_y = ((uint16)raw->red_y << 2) | raw->red_y_low; 73 display->green_x = ((uint16)raw->green_x << 2) | raw->green_x_low; 74 display->green_y = ((uint16)raw->green_y << 2) | raw->green_y_low; 75 display->blue_x = ((uint16)raw->blue_x << 2) | raw->blue_x_low; 76 display->blue_y = ((uint16)raw->blue_y << 2) | raw->blue_y_low; 77 display->white_x = ((uint16)raw->white_x << 2) | raw->white_x_low; 78 display->white_y = ((uint16)raw->white_y << 2) | raw->white_y_low; 79 } 80 81 82 static void 83 decode_std_timing(edid1_std_timing *timing, const edid1_std_timing_raw *raw) 84 { 85 timing->h_size = (raw->timing.h_size + 31) * 8; 86 timing->ratio = raw->timing.ratio; 87 88 switch (raw->timing.ratio) { 89 case 0: 90 timing->v_size = timing->h_size; 91 break; 92 case 1: 93 timing->v_size = timing->h_size * 3 / 4; 94 break; 95 case 2: 96 timing->v_size = timing->h_size * 4 / 5; 97 break; 98 case 3: 99 timing->v_size = timing->h_size * 9 / 16; 100 break; 101 } 102 timing->refresh = raw->timing.refresh + 60; 103 timing->id = raw->id; 104 } 105 106 107 static void 108 decode_whitepoint(edid1_whitepoint *whitepoint, const edid1_whitepoint_raw *raw) 109 { 110 whitepoint[0].index = raw->index1; 111 whitepoint[0].white_x = ((uint16)raw->white_x1 << 2) | raw->white_x1_low; 112 whitepoint[0].white_y = ((uint16)raw->white_y1 << 2) | raw->white_y1_low; 113 whitepoint[0].gamma = raw->gamma1; 114 115 whitepoint[1].index = raw->index2; 116 whitepoint[1].white_x = ((uint16)raw->white_x2 << 2) | raw->white_x2_low; 117 whitepoint[1].white_y = ((uint16)raw->white_y2 << 2) | raw->white_y2_low; 118 whitepoint[1].gamma = raw->gamma2; 119 } 120 121 122 static void 123 decode_detailed_timing( edid1_detailed_timing *timing, 124 const edid1_detailed_timing_raw *raw) 125 { 126 timing->pixel_clock = raw->pixel_clock; 127 timing->h_active = ((uint16)raw->h_active_high << 8) | raw->h_active; 128 timing->h_blank = ((uint16)raw->h_blank_high << 8) | raw->h_blank; 129 timing->v_active = ((uint16)raw->v_active_high << 8) | raw->v_active; 130 timing->v_blank = ((uint16)raw->v_blank_high << 8) | raw->v_blank; 131 timing->h_sync_off = ((uint16)raw->h_sync_off_high << 8) | raw->h_sync_off; 132 timing->h_sync_width = ((uint16)raw->h_sync_width_high << 8) | raw->h_sync_width; 133 timing->v_sync_off = ((uint16)raw->v_sync_off_high << 4) | raw->v_sync_off; 134 timing->v_sync_width = ((uint16)raw->v_sync_width_high << 4) | raw->v_sync_width; 135 timing->h_size = ((uint16)raw->h_size_high << 8) | raw->h_size; 136 timing->v_size = ((uint16)raw->v_size_high << 8) | raw->v_size; 137 timing->h_border = raw->h_border; 138 timing->v_border = raw->v_border; 139 timing->interlaced = raw->interlaced; 140 timing->stereo = raw->stereo; 141 timing->sync = raw->sync; 142 timing->misc = raw->misc; 143 } 144 145 146 //! copy string until 0xa, removing trailing spaces 147 static void 148 copy_str(char *dest, const uint8 *src, size_t len) 149 { 150 uint32 i; 151 152 // copy until 0xa 153 for (i = 0; i < len; ++i) { 154 if (*src == 0xa) 155 break; 156 157 *dest++ = *src++; 158 } 159 160 // remove trailing spaces 161 for (i = i - 1; i >= 0; --i) { 162 if (*dest-- != ' ') 163 break; 164 } 165 166 *++dest = 0; 167 } 168 169 170 static void 171 decode_detailed_monitor( edid1_detailed_monitor *monitor, 172 const edid1_detailed_monitor_raw *raw, bool enableExtra) 173 { 174 int i, j; 175 176 for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i, ++monitor, ++raw) { 177 monitor->monitor_desc_type = edid1_is_detailed_timing; 178 179 // workaround: normally, all four bytes must be zero for detailed 180 // description, but at least some Formac monitors violate that: 181 // they have some additional info that start at zero_4(!), 182 // so even if only the first two _or_ the other two bytes are 183 // zero, we accept it as a monitor description block 184 if (enableExtra 185 && ((raw->extra.zero_0[0] == 0 && raw->extra.zero_0[1] == 0) 186 || (raw->extra.zero_0[2] == 0 && raw->extra.zero_4 == 0))) { 187 monitor->monitor_desc_type = raw->extra.monitor_desc_type; 188 189 switch (raw->extra.monitor_desc_type) { 190 case edid1_serial_number: 191 copy_str( monitor->data.serial_number, 192 raw->extra.data.serial_number, EDID1_EXTRA_STRING_LEN ); 193 break; 194 case edid1_ascii_data: 195 copy_str( monitor->data.ascii_data, 196 raw->extra.data.ascii_data, EDID1_EXTRA_STRING_LEN ); 197 break; 198 case edid1_monitor_ranges: 199 monitor->data.monitor_range = raw->extra.data.monitor_range; 200 break; 201 case edid1_monitor_name: 202 copy_str( monitor->data.monitor_name, 203 raw->extra.data.monitor_name, EDID1_EXTRA_STRING_LEN ); 204 break; 205 case edid1_add_colour_pointer: 206 decode_whitepoint( monitor->data.whitepoint, 207 &raw->extra.data.whitepoint ); 208 break; 209 case edid1_add_std_timing: 210 for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) { 211 decode_std_timing(&monitor->data.std_timing[j], 212 &raw->extra.data.std_timing[j]); 213 } 214 break; 215 } 216 } else { 217 decode_detailed_timing(&monitor->data.detailed_timing, 218 &raw->detailed_timing); 219 } 220 } 221 } 222 223 224 // #pragma mark - 225 226 227 //! main function to decode edid data 228 void 229 edid_decode(edid1_info *edid, const edid1_raw *raw) 230 { 231 int i; 232 memset(edid, 0, sizeof(edid)); 233 234 decode_vendor(&edid->vendor, &raw->vendor); 235 decode_version(&edid->version, &raw->version); 236 decode_display(&edid->display, &raw->display); 237 238 edid->established_timing = raw->established_timing; 239 240 for (i = 0; i < EDID1_NUM_STD_TIMING; ++i) { 241 decode_std_timing(&edid->std_timing[i], &raw->std_timing[i]); 242 } 243 244 decode_detailed_monitor(edid->detailed_monitor, raw->detailed_monitor, 245 edid->version.version == 1 && edid->version.revision >= 1); 246 } 247