// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. // // StratoVirt is licensed under Mulan PSL v2. // You can use this software according to the terms and conditions of the Mulan // PSL v2. // You may obtain a copy of Mulan PSL v2 at: // http://license.coscl.org.cn/MulanPSL2 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. /// We use Leaky Bucket Algorithm to limit iops of block device and qmp. use byteorder::{BigEndian, ByteOrder, LittleEndian}; use log::warn; #[derive(Debug, Default)] struct EdidMode { xres: u32, yres: u32, byte: u32, xtra3: u32, bit: u32, dta: u32, } #[derive(Debug, Default)] pub struct EdidInfo { vendor: Vec<char>, name: Vec<char>, serial: u32, dpi: u32, prefx: u32, prefy: u32, maxx: u32, maxy: u32, } impl EdidInfo { pub fn new(vendor: &str, name: &str, dpi: u32, x: u32, y: u32) -> Self { EdidInfo { vendor: vendor.chars().collect(), name: name.chars().collect(), serial: 0, dpi, prefx: x, prefy: y, maxx: x, maxy: y, } } pub fn edid_array_fulfill(&mut self, edid_array: &mut [u8; 1024]) { // The format follows VESA ENHANCED EXTENDED DISPLAY IDENTIFICATION DATA STANDARD if self.vendor.len() != 3 { // HWV for 'HUAWEI TECHNOLOGIES CO., INC.' self.vendor = "HWV".chars().collect(); } if self.name.is_empty() { self.name = "STRA Monitor".chars().collect(); } if self.dpi == 0 { self.dpi = 100; } if self.prefx == 0 { self.prefx = 1024; } if self.prefy == 0 { self.prefy = 768; } let mut offset: usize = 54; let mut xtra3_offset: usize = 0; let mut dta_offset: usize = 0; if edid_array.len() >= 256 { dta_offset = 128; edid_array[126] += 1; self.fullfill_ext_dta(edid_array, dta_offset); } // Fixed header let header: u64 = 0x00FF_FFFF_FFFF_FF00; LittleEndian::write_u64(&mut edid_array[0..8], header); // ID Manufacturer Name let vendor_id: u16 = (((self.vendor[0] as u16 - '@' as u16) & 0x1f) << 10) | (((self.vendor[1] as u16 - '@' as u16) & 0x1f) << 5) | ((self.vendor[2] as u16 - '@' as u16) & 0x1f); BigEndian::write_u16(&mut edid_array[8..10], vendor_id); // ID Product Code LittleEndian::write_u16(&mut edid_array[10..12], 0x1234); // ID Serial Number LittleEndian::write_u32(&mut edid_array[12..16], self.serial); // Week of Manufacture edid_array[16] = 42; // Year of Manufacture or Model Year edid_array[17] = (2022 - 1990) as u8; // Version Number: defines EDID Structure Version 1, Revision 4. edid_array[18] = 0x01; // Revision Number edid_array[19] = 0x04; // Video Input Definition: digital, 8bpc, displayport edid_array[20] = 0xa5; // Horizontal Screen Size or Aspect Ratio edid_array[21] = (self.prefx * self.dpi / 2540) as u8; // Vertical Screen Size or Aspect Ratio edid_array[22] = (self.prefy * self.dpi / 2540) as u8; // Display Transfer Characteristic: display gamma is 2.2 edid_array[23] = 220 - 100; // Feature Support: std sRGB, preferred timing edid_array[24] = 0x06; let temp: [f32; 8] = [ 0.6400, 0.3300, 0.3000, 0.6000, 0.1500, 0.0600, 0.3127, 0.3290, ]; // Color Characteristics: 10 bytes self.fullfill_color_space(edid_array, temp); // 18 Byte Data Blocks: 72 bytes self.fullfill_desc_timing(edid_array, offset); offset += 18; self.fullfill_desc_range(edid_array, offset, 0xfd); offset += 18; if !self.name.is_empty() { self.fullfill_desc_text(edid_array, offset, 0xfc); offset += 18; } if self.serial != 0 { self.fullfill_desc_text(edid_array, offset, 0xff); offset += 18; } if offset < 126 { xtra3_offset = offset; self.fullfill_desc_xtra3_std(edid_array, xtra3_offset); offset += 18; } while offset < 126 { self.fullfill_desc_dummy(edid_array, offset); offset += 18; } // Established Timings: 3 bytes // Standard Timings: 16 bytes self.fullfill_modes(edid_array, xtra3_offset, dta_offset); // EXTENSION Flag and Checksum self.fullfill_checksum(edid_array) } fn fullfill_ext_dta(&mut self, edid_array: &mut [u8], offset: usize) { edid_array[offset] = 0x02; edid_array[offset + 1] = 0x03; edid_array[offset + 2] = 0x05; edid_array[offset + 3] = 0x00; // video data block edid_array[offset + 4] = 0x40; } fn fullfill_color_space(&mut self, edid_array: &mut [u8], arr: [f32; 8]) { let red_x: u32 = (arr[0] * 1024_f32 + 0.5) as u32; let red_y: u32 = (arr[0] * 1024_f32 + 0.5) as u32; let green_x: u32 = (arr[0] * 1024_f32 + 0.5) as u32; let green_y: u32 = (arr[0] * 1024_f32 + 0.5) as u32; let blue_x: u32 = (arr[0] * 1024_f32 + 0.5) as u32; let blue_y: u32 = (arr[0] * 1024_f32 + 0.5) as u32; let white_x: u32 = (arr[0] * 1024_f32 + 0.5) as u32; let white_y: u32 = (arr[0] * 1024_f32 + 0.5) as u32; edid_array[25] = (((red_x & 0x03) << 6) | ((red_y & 0x03) << 4) | ((green_x & 0x03) << 2) | (green_y & 0x03)) as u8; edid_array[26] = (((blue_x & 0x03) << 6) | ((blue_y & 0x03) << 4) | ((white_x & 0x03) << 2) | (white_y & 0x03)) as u8; edid_array[27] = (red_x >> 2) as u8; edid_array[28] = (red_y >> 2) as u8; edid_array[29] = (green_x >> 2) as u8; edid_array[30] = (green_y >> 2) as u8; edid_array[31] = (blue_x >> 2) as u8; edid_array[32] = (blue_y >> 2) as u8; edid_array[33] = (white_x >> 2) as u8; edid_array[34] = (white_y >> 2) as u8; } fn fullfill_desc_timing(&mut self, edid_array: &mut [u8], offset: usize) { // physical display size let xmm: u32 = self.prefx * self.dpi / 254; let ymm: u32 = self.prefy * self.dpi / 254; let xfront: u32 = self.prefx * 25 / 100; let xsync: u32 = self.prefx * 3 / 100; let xblank: u32 = self.prefx * 35 / 100; let yfront: u32 = self.prefy * 5 / 1000; let ysync: u32 = self.prefy * 5 / 1000; let yblank: u32 = self.prefy * 35 / 1000; let clock: u32 = 75 * (self.prefx + xblank) * (self.prefy + yblank); LittleEndian::write_u16(&mut edid_array[offset..offset + 2], clock as u16); edid_array[offset + 2] = (self.prefx & 0xff) as u8; edid_array[offset + 3] = (xblank & 0xff) as u8; edid_array[offset + 4] = (((self.prefx & 0xf00) >> 4) | ((xblank & 0xf00) >> 8)) as u8; edid_array[offset + 5] = (self.prefy & 0xff) as u8; edid_array[offset + 6] = (yblank & 0xff) as u8; edid_array[offset + 7] = (((self.prefy & 0xf00) >> 4) | ((yblank & 0xf00) >> 8)) as u8; edid_array[offset + 8] = (xfront & 0xff) as u8; edid_array[offset + 9] = (xsync & 0xff) as u8; edid_array[offset + 10] = (((yfront & 0x00f) << 4) | (ysync & 0x00f)) as u8; edid_array[offset + 11] = (((xfront & 0x300) >> 2) | ((xsync & 0x300) >> 4) | ((yfront & 0x030) >> 2) | ((ysync & 0x030) >> 4)) as u8; edid_array[offset + 12] = (xmm & 0xff) as u8; edid_array[offset + 13] = (ymm & 0xff) as u8; edid_array[offset + 14] = (((xmm & 0xf00) >> 4) | ((ymm & 0xf00) >> 8)) as u8; edid_array[offset + 17] = 0x18; } fn fullfill_desc_range(&mut self, edid_array: &mut [u8], offset: usize, desc_type: u8) { self.fullfill_desc_type(edid_array, offset, desc_type); // vertical (50 -> 125 Hz) edid_array[offset + 5] = 50; edid_array[offset + 6] = 125; // horizontal (30 -> 160 kHz) edid_array[offset + 7] = 30; edid_array[offset + 8] = 160; // max dot clock (1200 MHz) edid_array[offset + 9] = (1200 / 10) as u8; // no extended timing information edid_array[offset + 10] = 0x01; // padding edid_array[offset + 11] = b'\n'; for i in 12..18 { edid_array[offset + i] = b' '; } } fn fullfill_desc_text(&mut self, edid_array: &mut [u8], offset: usize, desc_type: u8) { self.fullfill_desc_type(edid_array, offset, desc_type); for i in 5..18 { edid_array[offset + i] = b' '; } if desc_type == 0xfc { // name for (index, c) in self.name.iter().enumerate() { edid_array[offset + 5 + index] = (*c) as u8; } } else if desc_type == 0xff { // serial LittleEndian::write_u32(&mut edid_array[offset + 5..offset + 9], self.serial); } else { warn!("Unexpected desc type"); } } fn fullfill_desc_xtra3_std(&mut self, edid_array: &mut [u8], offset: usize) { // additional standard timings 3 self.fullfill_desc_type(edid_array, offset, 0xf7); edid_array[offset + 4] = 10; } fn fullfill_desc_dummy(&mut self, edid_array: &mut [u8], offset: usize) { self.fullfill_desc_type(edid_array, offset, 0x10); } fn fullfill_desc_type(&mut self, edid_array: &mut [u8], offset: usize, desc_type: u8) { edid_array[offset] = 0; edid_array[offset + 1] = 0; edid_array[offset + 2] = 0; edid_array[offset + 3] = desc_type; edid_array[offset + 4] = 0; } fn fullfill_modes(&mut self, edid_array: &mut [u8], xtra3_offset: usize, dta_offset: usize) { let edid_modes = vec![ // dea/dta extension timings (all @ 50 Hz) EdidMode { xres: 5120, yres: 2160, dta: 125, ..Default::default() }, EdidMode { xres: 4096, yres: 2160, dta: 101, ..Default::default() }, EdidMode { xres: 3840, yres: 2160, dta: 96, ..Default::default() }, EdidMode { xres: 2560, yres: 1080, dta: 89, ..Default::default() }, EdidMode { xres: 2048, yres: 1152, ..Default::default() }, EdidMode { xres: 1920, yres: 1080, dta: 31, ..Default::default() }, // additional standard timings 3 (all @ 60Hz) EdidMode { xres: 1920, yres: 1440, xtra3: 11, bit: 5, ..Default::default() }, EdidMode { xres: 1920, yres: 1200, xtra3: 10, bit: 0, ..Default::default() }, EdidMode { xres: 1856, yres: 1392, xtra3: 10, bit: 3, ..Default::default() }, EdidMode { xres: 1792, yres: 1344, xtra3: 10, bit: 5, ..Default::default() }, EdidMode { xres: 1600, yres: 1200, xtra3: 9, bit: 2, ..Default::default() }, EdidMode { xres: 1680, yres: 1050, xtra3: 9, bit: 5, ..Default::default() }, EdidMode { xres: 1440, yres: 1050, xtra3: 8, bit: 1, ..Default::default() }, EdidMode { xres: 1440, yres: 900, xtra3: 8, bit: 5, ..Default::default() }, EdidMode { xres: 1360, yres: 768, xtra3: 8, bit: 7, ..Default::default() }, EdidMode { xres: 1280, yres: 1024, xtra3: 7, bit: 1, ..Default::default() }, EdidMode { xres: 1280, yres: 960, xtra3: 7, bit: 3, ..Default::default() }, EdidMode { xres: 1280, yres: 768, xtra3: 7, bit: 6, ..Default::default() }, // established timings (all @ 60Hz) EdidMode { xres: 1024, yres: 768, byte: 36, bit: 3, ..Default::default() }, EdidMode { xres: 800, yres: 600, byte: 35, bit: 0, ..Default::default() }, EdidMode { xres: 640, yres: 480, byte: 35, bit: 5, ..Default::default() }, ]; let mut std_offset: usize = 38; for mode in edid_modes { if (self.maxx != 0 && mode.xres > self.maxx) || (self.maxy != 0 && mode.yres > self.maxy) { continue; } if mode.byte != 0 { edid_array[mode.byte as usize] |= (1 << mode.bit) as u8; } else if mode.xtra3 != 0 && xtra3_offset != 0 { edid_array[xtra3_offset] |= (1 << mode.bit) as u8; } else if std_offset < 54 && self.fullfill_std_mode(edid_array, std_offset, mode.xres, mode.yres) == 0 { std_offset += 2; } if dta_offset != 0 && mode.dta != 0 { self.fullfill_ext_dta_mode(edid_array, dta_offset, mode.dta); } } while std_offset < 54 { self.fullfill_std_mode(edid_array, std_offset, 0, 0); std_offset += 2; } } fn fullfill_std_mode( &mut self, edid_array: &mut [u8], std_offset: usize, xres: u32, yres: u32, ) -> i32 { let aspect: u32; if xres == 0 || yres == 0 { edid_array[std_offset] = 0x01; edid_array[std_offset + 1] = 0x01; return 0; } else if xres * 10 == yres * 16 { aspect = 0; } else if xres * 3 == yres * 4 { aspect = 1; } else if xres * 4 == yres * 5 { aspect = 2; } else if xres * 9 == yres * 16 { aspect = 3; } else { return -1; } if (xres / 8) - 31 > 255 { return -1; } edid_array[std_offset] = ((xres / 8) - 31) as u8; edid_array[std_offset + 1] = (aspect << 6) as u8; 0 } fn fullfill_ext_dta_mode(&mut self, edid_array: &mut [u8], dta_offset: usize, dta: u32) { let index = edid_array[dta_offset + 2] as usize; edid_array[index] = dta as u8; edid_array[dta_offset + 2] += 1; edid_array[dta_offset + 4] += 1; } fn fullfill_checksum(&mut self, edid_array: &mut [u8]) { let mut sum: u32 = 0; for elem in edid_array.iter() { sum += *elem as u32; } sum &= 0xff; if sum != 0 { edid_array[127] = (0x100 - sum) as u8; } } }