drm-extras: replace edid-rs with libdisplay-info
Some checks are pending
Continuous Integration / format (push) Waiting to run
Continuous Integration / clippy-check (push) Waiting to run
Continuous Integration / check-msrv (push) Blocked by required conditions
Continuous Integration / check-minimal (push) Blocked by required conditions
Continuous Integration / smithay-check-features (push) Waiting to run
Continuous Integration / smithay-tests (push) Blocked by required conditions
Continuous Integration / smallvil-check (push) Blocked by required conditions
Continuous Integration / anvil-check-features (push) Blocked by required conditions
Continuous Integration / WLCS: Bad Buffer Test (push) Blocked by required conditions
Continuous Integration / WLCS: Core tests (push) Blocked by required conditions
Continuous Integration / WLCS: Output tests (push) Blocked by required conditions
Continuous Integration / WLCS: Pointer input tests (push) Blocked by required conditions
Continuous Integration / Documentation on Github Pages (push) Blocked by required conditions

This commit is contained in:
Christian Meissl 2024-08-31 19:30:26 +02:00 committed by Victoria Brekenfeld
parent 13164854de
commit ba75638167
10 changed files with 74 additions and 2687 deletions

View file

@ -88,8 +88,8 @@ use smithay::{
}, },
}; };
use smithay_drm_extras::{ use smithay_drm_extras::{
display_info,
drm_scanner::{DrmScanEvent, DrmScanner}, drm_scanner::{DrmScanEvent, DrmScanner},
edid::EdidInfo,
}; };
use tracing::{debug, error, info, trace, warn}; use tracing::{debug, error, info, trace, warn};
@ -929,9 +929,17 @@ impl AnvilState<UdevData> {
}) })
.unwrap_or(false); .unwrap_or(false);
let (make, model) = EdidInfo::for_connector(&device.drm, connector.handle()) let display_info = display_info::for_connector(&device.drm, connector.handle());
.map(|info| (info.manufacturer, info.model))
.unwrap_or_else(|| ("Unknown".into(), "Unknown".into())); let make = display_info
.as_ref()
.and_then(|info| info.make())
.unwrap_or_else(|| "Unknown".into());
let model = display_info
.as_ref()
.and_then(|info| info.model())
.unwrap_or_else(|| "Unknown".into());
if non_desktop { if non_desktop {
info!("Connector {} is non-desktop, setting up for leasing", output_name); info!("Connector {} is non-desktop, setting up for leasing", output_name);

View file

@ -6,15 +6,12 @@ license = "MIT"
authors = ["Bartłomiej Maryńczak <marynczakbartlomiej@gmail.com>"] authors = ["Bartłomiej Maryńczak <marynczakbartlomiej@gmail.com>"]
[dependencies] [dependencies]
edid-rs = "0.1.0" libdisplay-info = { version = "0.1.0", optional = true }
drm = { version = "0.12.0" } drm = { version = "0.12.0" }
[features] [features]
default = [] default = ["display-info"]
generate-hwdata = ["pkg-config"] display-info = ["libdisplay-info"]
[dev-dependencies.smithay] [dev-dependencies.smithay]
path = "../" path = "../"
[build-dependencies]
pkg-config = { version = "0.3.26", optional = true }

View file

@ -2,7 +2,7 @@
This crate contains some extra abstractions and helpers over DRM This crate contains some extra abstractions and helpers over DRM
- `edid` module is responsible for extraction of information from DRM connectors (`model` and `manufacturer`) - `display_info` module is responsible for extraction of information from DRM connectors (`model` and `manufacturer`)
- `drm_scanner` module contains helpers for detecting connector connected and disconnected events as well as mapping crtc to them. - `drm_scanner` module contains helpers for detecting connector connected and disconnected events as well as mapping crtc to them.
- `ConnectorScanner` is responsible for tracking connected/disconnected events. - `ConnectorScanner` is responsible for tracking connected/disconnected events.
- `CrtcMapper` trait and `SimpleCrtcMapper` are meant for mapping crtc to connector. - `CrtcMapper` trait and `SimpleCrtcMapper` are meant for mapping crtc to connector.

View file

@ -1,59 +0,0 @@
fn main() {
#[cfg(feature = "generate-hwdata")]
generate_hwdata();
}
#[cfg(feature = "generate-hwdata")]
fn generate_hwdata() {
use std::{
fs,
path::{Path, PathBuf},
};
let pkg_path = pkg_config::get_variable("hwdata", "pkgdatadir");
// Old versions of hwdata don't have .pc file, so let's guess
let pkg_path = pkg_path.as_deref().unwrap_or("/usr/share/hwdata");
let pnp_ids_path = PathBuf::from(pkg_path).join("pnp.ids");
println!(
"cargo:rerun-if-changed={}",
pnp_ids_path.as_os_str().to_string_lossy()
);
if let Ok(file) = fs::read_to_string(pnp_ids_path) {
let out_dir = PathBuf::from("src").join("hwdata").join("generated");
let dest_path = Path::new(&out_dir).join("pnp_ids.rs");
let i1 = " ".repeat(4);
let i2 = " ".repeat(8);
let mut output = Vec::new();
output.push("#[rustfmt::skip]".into());
output.push("pub fn pnp_id_to_name(vendor: &[char; 3]) -> Option<&'static str> {".into());
output.push(i1.clone() + "match vendor {");
for line in file.lines() {
let mut segment = line.split('\t');
let mut code = segment.next().unwrap().chars();
let n1 = code.next().unwrap();
let n2 = code.next().unwrap();
let n3 = code.next().unwrap();
let name = segment.next().unwrap();
output.push(format!("{i2}['{n1}', '{n2}', '{n3}'] => Some(\"{name}\"),"));
}
output.push(i2 + "_ => None,");
output.push(i1 + "}");
output.push("}".into());
let output = output.join("\n");
fs::write(dest_path, output).unwrap();
}
}

View file

@ -2,8 +2,8 @@ use std::{collections::HashMap, path::PathBuf, time::Duration};
use ::drm::control::{connector, crtc}; use ::drm::control::{connector, crtc};
use smithay_drm_extras::{ use smithay_drm_extras::{
display_info,
drm_scanner::{self, DrmScanEvent}, drm_scanner::{self, DrmScanEvent},
edid::EdidInfo,
}; };
use smithay::{ use smithay::{
@ -135,9 +135,17 @@ impl State {
if let Some(device) = self.devices.get_mut(&node) { if let Some(device) = self.devices.get_mut(&node) {
let name = format!("{}-{}", connector.interface().as_str(), connector.interface_id()); let name = format!("{}-{}", connector.interface().as_str(), connector.interface_id());
let (manufacturer, model) = EdidInfo::for_connector(&device.drm, connector.handle()) let display_info = display_info::for_connector(&device.drm, connector.handle());
.map(|info| (info.manufacturer, info.model))
.unwrap_or_else(|| ("Unknown".into(), "Unknown".into())); let manufacturer = display_info
.as_ref()
.and_then(|info| info.make())
.unwrap_or_else(|| "Unknown".into());
let model = display_info
.as_ref()
.and_then(|info| info.model())
.unwrap_or_else(|| "Unknown".into());
println!("Connected:"); println!("Connected:");
dbg!(name); dbg!(name);
@ -166,7 +174,11 @@ impl State {
return; return;
}; };
for event in device.drm_scanner.scan_connectors(&device.drm) { for event in device
.drm_scanner
.scan_connectors(&device.drm)
.expect("failed to scan connectors")
{
match event { match event {
DrmScanEvent::Connected { DrmScanEvent::Connected {
connector, connector,

View file

@ -0,0 +1,37 @@
//! # EDID - Extended Display Identification Data
//!
//! This module is meant to help with extraction of EDID data from connectors
//!
//! ```no_run
//! # mod helpers { include!("./docs/doctest_helpers.rs"); };
//! # let drm_device: helpers::FakeDevice = todo!();
//! # let connector = todo!();
//! use smithay_drm_extras::display_info;
//!
//! let info = display_info::for_connector(&drm_device, connector).unwrap();
//!
//! println!("Monitor name: {}", info.model());
//! println!("Manufacturer name: {}", info.make());
//! ```
use drm::control::{connector, Device as ControlDevice};
use libdisplay_info::info::Info;
/// Try to read the [`Info`] from the connector EDID property
pub fn for_connector(device: &impl ControlDevice, connector: connector::Handle) -> Option<Info> {
let props = device.get_properties(connector).ok()?;
let (info, value) = props
.into_iter()
.filter_map(|(handle, value)| {
let info = device.get_property(handle).ok()?;
Some((info, value))
})
.find(|(info, _)| info.name().to_str() == Ok("EDID"))?;
let blob = info.value_type().convert_value(value).as_blob()?;
let data = device.get_property_blob(blob).ok()?;
Info::parse_edid(&data).ok()
}

View file

@ -1,89 +0,0 @@
//! # EDID - Extended Display Identification Data
//!
//! This module is meant to help with extraction of EDID data from connectors
//!
//! ```no_run
//! # mod helpers { include!("./docs/doctest_helpers.rs"); };
//! # let drm_device: helpers::FakeDevice = todo!();
//! # let connector = todo!();
//! use smithay_drm_extras::edid::EdidInfo;
//!
//! let info = EdidInfo::for_connector(&drm_device, connector).unwrap();
//!
//! println!("Monitor name: {}", info.model);
//! println!("Manufacturer name: {}", info.manufacturer);
//! ```
use drm::control::{connector, Device as ControlDevice, PropertyValueSet};
use edid_rs::MonitorDescriptor;
use super::hwdata;
/// Information about monitor, acquired from EDID
#[derive(Debug, Clone)]
pub struct EdidInfo {
/// Monitor name
pub model: String,
/// Name of manufacturer of this monitor
pub manufacturer: String,
}
impl EdidInfo {
/// Get EDID info from supplied connector
pub fn for_connector(device: &impl ControlDevice, connector: connector::Handle) -> Option<EdidInfo> {
device
.get_properties(connector)
.ok()
.and_then(|props| get_edid(device, &props))
.map(|edid| EdidInfo {
model: get_monitor_name(&edid),
manufacturer: get_manufacturer_name(&edid),
})
}
}
fn get_edid(device: &impl ControlDevice, props: &PropertyValueSet) -> Option<edid_rs::EDID> {
let (info, value) = props
.into_iter()
.filter_map(|(handle, value)| {
let info = device.get_property(*handle).ok()?;
Some((info, value))
})
.find(|(info, _)| info.name().to_str() == Ok("EDID"))?;
let blob = info.value_type().convert_value(*value).as_blob()?;
let data = device.get_property_blob(blob).ok()?;
let mut reader = std::io::Cursor::new(data);
edid_rs::parse(&mut reader).ok()
}
fn get_manufacturer_name(edid: &edid_rs::EDID) -> String {
let id = edid.product.manufacturer_id;
let code = [id.0, id.1, id.2];
hwdata::pnp_id_to_name(&code)
.map(|name| name.to_string())
.unwrap_or_else(|| {
code.into_iter()
.map(|v| (v as u8).to_string())
.collect::<Vec<String>>()
.join("_")
})
}
fn get_monitor_name(edid: &edid_rs::EDID) -> String {
edid.descriptors
.0
.iter()
.find_map(|desc| {
if let MonitorDescriptor::MonitorName(name) = desc {
Some(name.clone())
} else {
None
}
})
.unwrap_or_else(|| edid.product.product_code.to_string())
}

File diff suppressed because it is too large Load diff

View file

@ -1,7 +0,0 @@
mod generated {
include!("./generated/pnp_ids.rs");
}
pub fn pnp_id_to_name(vendor: &[char; 3]) -> Option<&'static str> {
generated::pnp_id_to_name(vendor)
}

View file

@ -2,15 +2,15 @@
//! //!
//! This crate contains some extra abstractions and helpers over DRM //! This crate contains some extra abstractions and helpers over DRM
//! //!
//! - [`edid`] is responsible for extraction of information from DRM connectors //! - [`display_info`] is responsible for extraction of information from DRM connectors
//! - [`drm_scanner`] is responsible for detecting connector connected and //! - [`drm_scanner`] is responsible for detecting connector connected and
//! disconnected events, as well as mapping CRTC to them. //! disconnected events, as well as mapping CRTC to them.
//! //!
//! ### Features //! ### Features
//! - `generate-hwdata` - If enabled [hwdata](https://github.com/vcrhonek/hwdata) code will be regenerated using `hwdata` system package //! - `display_info` - If enabled `display_info` functionality is enabled through `libdisplay-info` integration
#![warn(missing_docs, missing_debug_implementations)] #![warn(missing_docs, missing_debug_implementations)]
#[cfg(feature = "display-info")]
pub mod display_info;
pub mod drm_scanner; pub mod drm_scanner;
pub mod edid;
mod hwdata;