use pciids::PciIdData; use anyhow::{Context, Result}; #[derive(structopt::StructOpt)] struct Args { #[structopt(long = "pci-ids-file")] #[cfg_attr( target_os = "linux", structopt(default_value = "/usr/share/misc/pci.ids") )] #[cfg_attr(target_os = "redox", structopt(default_value = "/share/misc/pci.ids"))] pci_ids_file: String, #[structopt(subcommand)] subcommand: Subcommand, } fn parse_from_hex_u8(src: &str) -> Result { let num = u8::from_str_radix(src, 16)?; Ok(num) } fn parse_from_hex_u16(src: &str) -> Result { let num = u16::from_str_radix(src, 16)?; Ok(num) } fn parse_from_hex_u16u16(src: &str) -> Result<(u16, u16)> { let n = u32::from_str_radix(src, 16)?; Ok(((n >> 16) as u16, (0xFF & n) as u16)) } #[derive(Debug, PartialEq, structopt::StructOpt)] enum Subcommand { Device(Device), Class(Class), } #[derive(Debug, PartialEq, structopt::StructOpt)] struct Device { #[structopt(parse(try_from_str = parse_from_hex_u16))] vendor: u16, #[structopt(parse(try_from_str = parse_from_hex_u16))] device: Option, #[structopt(parse(try_from_str = parse_from_hex_u16u16))] subsystem: Option<(u16, u16)>, } #[derive(Debug, PartialEq, structopt::StructOpt)] struct Class { #[structopt(parse(try_from_str = parse_from_hex_u8))] class: u8, #[structopt(parse(try_from_str = parse_from_hex_u8))] subclass: Option, #[structopt(parse(try_from_str = parse_from_hex_u8))] prog_interface: Option, } #[paw::main] fn main(args: Args) -> Result<()> { let mut pci_id_data = PciIdData::new(); let pci_id_file_contents = std::fs::read_to_string(args.pci_ids_file).expect("cannot read file"); pci_id_data.add_pci_ids_data(&mut pci_id_file_contents.as_bytes())?; match args.subcommand { Subcommand::Device(d) => print_device(d, &pci_id_data)?, Subcommand::Class(c) => print_class(c, &pci_id_data)?, }; Ok(()) } fn print_device(device_args: Device, pci_data: &PciIdData) -> Result<()> { let mut msg = String::from(format!( "Looking up about vendor[:device][:subsystem]: {:01$X}", device_args.vendor, 4 )); if let Some(device) = device_args.device { msg.push_str(format!(":{:01$X}", device, 4).as_str()); if let Some(subsystem) = device_args.subsystem { msg.push_str(format!(".{:02$X}{:02$X}", subsystem.0, subsystem.1, 4).as_str()); } } println!("{}", msg); let vendor = pci_data .get_vendor(&device_args.vendor) .context("Vendor not found.")?; println!("Vendor name: {}", vendor.name); if let Some(device_id) = device_args.device { if let Ok(device) = vendor.get_device(&device_id) { println!("Device name: {}", device.name); if let Some(subsystem_id) = device_args.subsystem { if let Ok(subsystem) = device.get_subsystem(&(subsystem_id.0, subsystem_id.1)) { println!("Subsystem name: {}", subsystem.name); } else { println!("Subsystem not found."); } } } else { println!("Device not found."); } } Ok(()) } fn print_class(class_args: Class, pci_data: &PciIdData) -> Result<()> { let mut msg = String::from(format!( "Looking up info about class[:subclass][.prog_interface]: {:01$X}", class_args.class, 2 )); if let Some(subclass) = class_args.subclass { msg.push_str(format!(":{:01$X}", subclass, 2).as_str()); if let Some(prog_interface) = class_args.prog_interface { msg.push_str(format!(".{:01$X}", prog_interface, 2).as_str()); } } println!("{}", msg); let class = pci_data .get_class(&class_args.class) .context("Vendor not found")?; println!("Class name: {}", class.name); if let Some(subclass_id) = &class_args.subclass { let subclass = class .get_subclass(&subclass_id) .context("Subclass not found")?; println!("Subclass name: {}", subclass.name); if let Some(prog_interface_id) = &class_args.prog_interface { let prog_interface = subclass .get_prog_interface(prog_interface_id) .context("Programming interface not found.")?; println!("Programming interface name: {}", prog_interface.name); } } Ok(()) }