Skip to content

Commit 7126a8b

Browse files
committed
windows: Add option to dump versions of all drivers
Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent 0fe7727 commit 7126a8b

6 files changed

Lines changed: 318 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ On UEFI and FreeBSD raw port I/O is used - on Linux this can also be used as a f
108108
- [x] HDMI Expansion Card (`--dp-hdmi-update`)
109109
- [x] DisplayPort Expansion Card (`--dp-hdmi-update`)
110110
- [ ] Audio Expansion Card
111+
- [x] Get driver version for all devices (Windows only) (`--drivers`)
111112

112113
###### System Status
113114

framework_lib/src/commandline/clap_std.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ struct ClapCli {
246246
#[arg(long)]
247247
s0ix_counter: bool,
248248

249+
/// Display Windows Driver versions
250+
#[arg(long)]
251+
drivers: bool,
252+
249253
/// Hash a file of arbitrary data
250254
#[arg(long)]
251255
hash: Option<std::path::PathBuf>,
@@ -466,6 +470,7 @@ pub fn parse(args: &[String]) -> Cli {
466470
ec_hib_delay: args.ec_hib_delay,
467471
uptimeinfo: args.uptimeinfo,
468472
s0ix_counter: args.s0ix_counter,
473+
drivers: args.drivers,
469474
hash: args.hash.map(|x| x.into_os_string().into_string().unwrap()),
470475
driver: args.driver,
471476
pd_addrs,

framework_lib/src/commandline/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ use crate::uefi::enable_page_break;
6666
#[cfg(feature = "rusb")]
6767
use crate::usbhub::check_usbhub_version;
6868
use crate::util::{self, Config, Platform, PlatformFamily};
69+
#[cfg(target_os = "windows")]
70+
use crate::wmi;
6971
#[cfg(feature = "hidapi")]
7072
use hidapi::HidApi;
7173
use sha2::{Digest, Sha256, Sha384, Sha512};
@@ -217,6 +219,7 @@ pub struct Cli {
217219
pub uptimeinfo: bool,
218220
pub s0ix_counter: bool,
219221
pub hash: Option<String>,
222+
pub drivers: bool,
220223
pub pd_addrs: Option<(u16, u16, u16)>,
221224
pub pd_ports: Option<(u8, u8, u8)>,
222225
pub help: bool,
@@ -1687,6 +1690,11 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
16871690
}
16881691
} else if let Some(ec_bin_path) = &args.flash_rw_ec {
16891692
flash_ec(&ec, ec_bin_path, EcFlashType::Rw, args.dry_run);
1693+
} else if args.drivers {
1694+
#[cfg(target_os = "windows")]
1695+
wmi::print_drivers();
1696+
#[cfg(not(target_os = "windows"))]
1697+
println!("Driver Version only supported on Windows");
16901698
} else if let Some(hash_file) = &args.hash {
16911699
println!("Hashing file: {}", hash_file);
16921700
#[cfg(feature = "uefi")]

framework_lib/src/commandline/uefi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub fn parse(args: &[String]) -> Cli {
8080
ec_hib_delay: None,
8181
uptimeinfo: false,
8282
s0ix_counter: false,
83+
drivers: false,
8384
hash: None,
8485
// This is the only driver that works on UEFI
8586
driver: Some(CrosEcDriverType::Portio),

framework_lib/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ pub mod smbios;
4949
#[cfg(feature = "uefi")]
5050
pub mod uefi;
5151
mod util;
52+
#[cfg(target_os = "windows")]
53+
pub mod wmi;
5254

5355
pub mod built_info {
5456
// The file has been placed there by the build script.

framework_lib/src/wmi.rs

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
use std::collections::HashMap;
2+
use wmi::*;
3+
4+
// TODO:
5+
// - [ ] Critical
6+
// - [ ] Figure out why the CSME version is old
7+
// - Looks like that depends on the CPU/CSME type
8+
// - [x] Figure out how "Intel Chipset" shows up, I can't find any drivers
9+
// - It's present in Win32_Product
10+
// - [ ] Intel WiFi driver in Win32_SystemDriver is old, but in Win32_PnpSignedDriver is correct. Which one is used?
11+
// - [x] Provide nice alias for driver names
12+
// - [ ] Display drivers even when they're missing to make sure we find those that didn't install
13+
// - [ ] Make more efficient by querying only the drivers we care about
14+
// - [ ] Figure out why IGCC versios shows same as graphics driver
15+
// - [ ] Figure out how to read HSA "Realtek Audio Console" version
16+
17+
// Helpful commands
18+
// Win32_SystemDriver
19+
// get-wmiobject Win32_SystemDriver | select DisplayName,Name,@{n="version";e={(gi $_.pathname).VersionInfo.FileVersion}},PathName
20+
// Get-WmiObject -query "SELECT * FROM CIM_Datafile WHERE Name = 'C:\Windows\system32\drivers\xinputhid.sys'"
21+
// Get-WmiObject -query "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode <> 0"
22+
//
23+
// Win32_PnpSignedDriver
24+
// get-wmiobject Win32_PnpSignedDriver | select Manufacturer,DeviceName,HardwareID,DriverVersion
25+
// get-wmiobject Win32_PnpSignedDriver | where manufacturer -like 'Goodix' | select Manufacturer,DeviceName,HardwareID,DriverVersion
26+
// get-wmiobject Win32_PnpSignedDriver | where manufacturer -like 'Intel' | select Manufacturer,DeviceName,HardwareID,DriverVersion
27+
//
28+
// Win32_Product
29+
// Get-WmiObject -Class Win32_Product | select IdentifyingNumber, Name, Version
30+
31+
pub fn print_yellow_bangs() {
32+
println!("Devices with Yellow Bangs");
33+
debug!("Opening WMI");
34+
let wmi_con = WMIConnection::new(COMLibrary::new().unwrap()).unwrap();
35+
debug!("Querying WMI");
36+
let results: Vec<HashMap<String, Variant>> = wmi_con
37+
.raw_query("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode <> 0")
38+
.unwrap();
39+
40+
if results.is_empty() {
41+
println!(" None");
42+
return;
43+
}
44+
45+
for bang in results.iter() {
46+
// println!(" {:#?}", results);
47+
// TODO: Unpack the Variant types
48+
// TODO: Use serde
49+
let description = if let Variant::String(s) = &bang["Description"] {
50+
s
51+
} else {
52+
&"".to_string()
53+
};
54+
println!(" {}", description);
55+
println!(" Compatible IDs: {:?}", &bang["CompatibleID"]);
56+
println!(" Hardware IDs: {:?}", &bang["HardwareID"]);
57+
println!(" DeviceID: {:?}", &bang["DeviceID"]);
58+
println!(" PNPDeviceID: {:?}", &bang["PNPDeviceID"]);
59+
println!(
60+
" ConfigManagerErrorCode {:?}",
61+
&bang["ConfigManagerErrorCode"]
62+
);
63+
println!(" Status {:?}", &bang["Status"]);
64+
// Other values that don't seem to have useful information
65+
// ConfigManagerUserConfig: Bool (false)
66+
// ErrorCleared: ? (Null)
67+
// CreationClassName: String ("Win32_PnPEntity")
68+
// Present: Bool (true)
69+
// InstallDate: ? (Null)
70+
// ErrorDescription: ? (Null)
71+
// Caption: String ("Multimedia Audio Controller")
72+
// LastErrorCode: ? (Null)
73+
// Availability: ? (Null)
74+
// PowerManagementCapabilities: Array ([])
75+
// PowerManagementSupported: ? (Null)
76+
// PNPClass: ? (Null)
77+
// StatusInfo: ? (Null)
78+
}
79+
}
80+
81+
const PNP_DRIVERS: &[&str] = &[
82+
// Manufacturer DeviceName HardWareID DriverVersion
83+
// ------------ ---------- ---------- -------------
84+
// Goodix Framework Fingerprint Reader USB\VID_27C6&PID_609C&REV_0100 3.12804.0.240
85+
"Framework Fingerprint Reader",
86+
// TODO: Wrong version
87+
// Intel Corporation Intel(R) Graphics Command Center SWC\101.5522_VEN8086_IGCC
88+
// "Intel(R) Graphics Command Center",
89+
90+
// Intel Corporation Intel(R) Wi-Fi 6E AX210 160MHz PCI\VEN_8086&DEV_2725&SUBSYS_00248086&REV_1A 23.60.0.10
91+
"Intel(R) Wi-Fi 6E AX210 160MHz",
92+
// Don't need, already in system_drivers
93+
// Intel Corporation Intel(R) Wireless Bluetooth(R) USB\VID_8087&PID_0032&REV_0000 23.60.0.1
94+
// "Intel(R) Wireless Bluetooth(R)",
95+
96+
// Intel(R) Platform Monito… Intel(R) Platform Monitoring Technology (PMT) Driver PCI\VEN_8086&DEV_7D0D&SUBSYS_0009F111&REV_01 3.1.2.2
97+
"Intel(R) Platform Monitoring Technology (PMT) Driver",
98+
// Also in system_drivers
99+
// Not using the one here, because it doesn't show up when the card isn't plugged in
100+
// Genesys Logic Framework SD Expansion Card USB\VID_32AC&PID_0009&REV_0003 4.5.10.201
101+
];
102+
103+
const PRODUCTS: &[&str] = &[
104+
// TODO: Can I rely on the IdentifyingNumber GUID?
105+
// IdentifyingNumber Name Version
106+
// ----------------- ---- -------
107+
// {BAB97289-552B-49D5-B1E7-95DB4E4D2DEF} Intel(R) Chipset Device Software 10.1.19627.84…
108+
"Intel(R) Chipset Device Software",
109+
// {00000060-0230-1033-84C8-B8D95FA3C8C3} Intel(R) Wireless Bluetooth(R) 23.60.0.1
110+
// {1C1EBF97-5EC2-4C01-BCFC-037D140796B4} Intel(R) Serial IO 30.100.2405.44
111+
];
112+
113+
pub fn print_drivers() {
114+
print_yellow_bangs();
115+
116+
println!("Drivers");
117+
let wmi_con = WMIConnection::new(COMLibrary::new().unwrap()).unwrap();
118+
119+
// PNP Drivers
120+
let results: Vec<HashMap<String, Variant>> = wmi_con
121+
.raw_query(
122+
"SELECT Manufacturer,DeviceName,HardwareID,DriverVersion FROM Win32_PnpSignedDriver",
123+
)
124+
.unwrap();
125+
for val in results.iter() {
126+
let device_name = if let Variant::String(s) = &val["DeviceName"] {
127+
s
128+
} else {
129+
&"".to_string()
130+
};
131+
let version = if let Variant::String(s) = &val["DriverVersion"] {
132+
s
133+
} else {
134+
&"".to_string()
135+
};
136+
137+
// Skip those that we don't care about
138+
if !PNP_DRIVERS.contains(&device_name.as_str()) {
139+
continue;
140+
}
141+
println!(" {}", device_name);
142+
println!(" Version: {}", version);
143+
}
144+
145+
// Products
146+
let results: Vec<HashMap<String, Variant>> = wmi_con
147+
.raw_query("SELECT IdentifyingNumber, Name, Version FROM Win32_Product")
148+
.unwrap();
149+
for val in results.iter() {
150+
let name = if let Variant::String(s) = &val["Name"] {
151+
s
152+
} else {
153+
&"".to_string()
154+
};
155+
let version = if let Variant::String(s) = &val["Version"] {
156+
s
157+
} else {
158+
&"".to_string()
159+
};
160+
161+
// Skip those that we don't care about
162+
if !PRODUCTS.contains(&name.as_str()) {
163+
continue;
164+
}
165+
println!(" {}", name);
166+
println!(" Version: {}", version);
167+
}
168+
169+
// System Drivers
170+
//const system_drivers: HashMap<&str, Option<&str>> = HashMap::from([
171+
let system_drivers = HashMap::from([
172+
// [ ] 13 Goodix
173+
// TODO: Can find via Win32_PnpSignedDriver, Manufacturer 'Goodix', DeviceName 'Framework Fingerprint Reader'
174+
// HardwareID: USB\VID_27C6&PID_609C&REV_0100
175+
176+
// [ ] 12 Intel Platform Monitoring Technology
177+
// Can find in PNP
178+
179+
// [x] 11 Intel PROSet Bluetooth
180+
("ibtusb", None), // Intel(R) Wireless Bluetooth(R)
181+
// [ ] 10 Intel PROSet WiFi
182+
// TODO: The first two show old version - Is the wrong version used?
183+
// "Netwtw14", // Intel® Smart Sound Technology BUS
184+
// "Netwtw10", // Intel® Smart Sound Technology BUS
185+
// "Netwtw16", // This one has the correct version, but it doesn't show up
186+
187+
// [x] 09 Realtek Audio
188+
("IntcAzAudAddService", None), // Service for Realtek HD Audio (WDM)
189+
// [x] 08 Intel Smart Sound Technology
190+
("IntcAudioBus", None), // Intel® Smart Sound Technology BUS
191+
//"IntcOED", // Intel® Smart Sound Technology OED
192+
//"IntcUSB", // Intel® Smart Sound Technology for USB Audio
193+
194+
// [x] 07 Intel Dynamic Tuning Technology
195+
("ipf_acpi", Some("Intel Dynamic Tuning Technology")),
196+
// "ipf_cpu",
197+
// "ipf_lf",
198+
199+
// [x] 06 Intel NPU
200+
("npu", Some("Intel NPU")),
201+
// [x] 05 Intel Graphics
202+
("igfxn", Some("Intel Graphics")), // igfxn
203+
// [x] 04 Intel Serial IO
204+
// Don't need to show GPIO and I2C versions, we don't need GPIO driver anyways
205+
// "iaLPSS2_GPIO2_MTL", // Serial IO GPIO Driver v2
206+
// "iagpio", // Intel Serial IO GPIO Controller Driver
207+
// "iai2c", // Serial IO I2C Host Controller
208+
// "iaLPSS2i_GPIO2"
209+
// "iaLPSS2i_GPIO2_BXT_P",
210+
// "iaLPSS2i_GPIO2_CNL",
211+
// "iaLPSS2i_GPIO2_GLK",
212+
("iaLPSS2_I2C_MTL", Some("Intel Serial IO")), // Serial IO I2C Driver v2
213+
// "iaLPSS2i_I2C",
214+
// "iaLPSS2i_I2C_BXT_P",
215+
// "iaLPSS2i_I2C_CNL",
216+
// "iaLPSS2i_I2C_GLK",
217+
218+
// [ ] 03 Intel Management Engine
219+
// TODO: Shows old version 2406.5.5.0 instead of 2409.5.63.0
220+
("MEIx64", None), // Intel(R) Management Engine Interface
221+
// [x] 02 Intel GNA Scoring Accelerator
222+
("IntelGNA", None), // Intel(R) GNA Scoring Accelerator service
223+
// [ ] 01 Intel Chipset
224+
// TODO: How to find?
225+
// Can't find it anywhere, not in Device Manager, not in Win32_SystemDriver, not in Win32_PnpSignedDriver
226+
227+
// Framework provided drivers
228+
// Realtek USB FE/1GbE/2.5GbE NIC Family Windows 10 64-bit Driver
229+
(
230+
"rtux64w10",
231+
Some("Realtek/Framework Ethernet Expansion Card"),
232+
),
233+
// Genesys Logic Storage Driver
234+
("GeneStor", Some("Genesys/Framework SD Expansion Card")),
235+
//"IntcAzAudAddService", // Service for Realtek HD Audio (WDM)
236+
//"intelpmax", // Intel(R) Dynamic Device Peak Power Manager Driver
237+
//"IntelPMT", // Intel(R) Platform Monitoring Technology Service
238+
]);
239+
240+
let results: Vec<HashMap<String, Variant>> = wmi_con
241+
.raw_query("SELECT DisplayName,Name,PathName FROM Win32_SystemDriver")
242+
.unwrap();
243+
for val in results.iter() {
244+
let display_name = if let Variant::String(s) = &val["DisplayName"] {
245+
s
246+
} else {
247+
&"".to_string()
248+
};
249+
let name = if let Variant::String(s) = &val["Name"] {
250+
s
251+
} else {
252+
&"".to_string()
253+
};
254+
let path_name = if let Variant::String(s) = &val["PathName"] {
255+
s
256+
} else {
257+
&"".to_string()
258+
};
259+
260+
// select * from CIM_Datafile" & _ " where Name = '" & Replace(strPath, "\", "\\") &
261+
// C:\Windows\system32\drivers\xinputhid.sys
262+
// Get-WmiObject -query "SELECT Version FROM CIM_Datafile WHERE Name = 'C:\\Windows\\system32\\drivers\\xinputhid.sys'"
263+
if !path_name.starts_with("C:") {
264+
debug!("Skipping path_name: {:?}", path_name);
265+
// TODO: Probably a UNC path, not sure how to handle it, let's skip it
266+
continue;
267+
}
268+
let query = format!(
269+
"SELECT Version FROM CIM_Datafile WHERE Name = '{}'",
270+
path_name.replace("\\", "\\\\")
271+
);
272+
let results: Vec<HashMap<String, Variant>> = wmi_con.raw_query(query).unwrap();
273+
let version = if let Variant::String(s) = &results[0]["Version"] {
274+
s
275+
} else {
276+
""
277+
};
278+
279+
// Skip those that we don't care about
280+
let str_name: &str = name;
281+
//if let Ok(alias) = system_drivers.binary_search_by(|(k, _)| k.cmp(&str_name)).map(|x| system_drivers[x].1) {
282+
if let Some(alias) = system_drivers.get(&str_name) {
283+
let alias = if let Some(alias) = alias {
284+
*alias
285+
} else {
286+
display_name
287+
};
288+
println!(" {}", alias);
289+
debug!(" Display: {}", display_name);
290+
debug!(" Name: {}", name);
291+
debug!(" Path: {}", path_name);
292+
println!(" Version: {}", version);
293+
} else {
294+
//println!("Not found: {}", display_name);
295+
//println!(" Name: '{}'", name);
296+
//debug!(" Path: {}", path_name);
297+
//println!(" Version: {}", version);
298+
continue;
299+
}
300+
}
301+
}

0 commit comments

Comments
 (0)