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