Skip to main content

lspci/
device.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4use crate::Args;
5use crate::capability::{Capability, ExtendedCapability};
6use crate::config::{CommandRegister, StatusRegister, Type00Config};
7use crate::db::PciDb;
8use crate::util::{Hexdumper, format_bytes};
9use fidl_fuchsia_hardware_pci::PciDevice as FidlDevice;
10use std::fmt;
11use zerocopy::Ref;
12
13pub struct Device<'a> {
14    pub device: &'a FidlDevice,
15    pub class: Option<String>,
16    pub name: Option<String>,
17    pub cfg: Ref<&'a [u8], Type00Config>,
18    pub args: &'a Args,
19}
20
21struct BaseAddress<'a>(&'a fidl_fuchsia_hardware_pci::BaseAddress);
22impl<'a> fmt::Display for BaseAddress<'a> {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        write!(
25            f,
26            "Region {}: {} at {:#x} ({}-bit, {}) [size={}]\n",
27            self.0.id,
28            if self.0.is_memory { "Memory" } else { "I/O ports" },
29            self.0.address,
30            if self.0.is_64bit { 64 } else { 32 },
31            if self.0.is_prefetchable { "prefetchable" } else { "non-prefetchable" },
32            format_bytes(self.0.size)
33        )
34    }
35}
36
37impl<'a> Device<'a> {
38    pub fn new(device: &'a FidlDevice, id_db: &Option<PciDb<'_>>, args: &'a Args) -> Self {
39        let cfg = Type00Config::new(&device.config);
40        let (class, name) = if let Some(db) = id_db {
41            (
42                db.find_class(cfg.base_class, cfg.sub_class, Some(cfg.program_interface)),
43                db.find_device(cfg.vendor_id, cfg.device_id),
44            )
45        } else {
46            (None, None)
47        };
48        Device { device, class, name, cfg, args }
49    }
50
51    pub fn print_common_header(&self, f: &'a mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(
53            f,
54            "{:02x}:{:02x}.{:1x}",
55            self.device.bus_id, self.device.device_id, self.device.function_id
56        )?;
57        if let Some(class) = &self.class {
58            if !self.args.only_print_numeric {
59                write!(f, " {}", class)?;
60            }
61        }
62        if self.class.is_none() || self.args.print_numeric || self.args.only_print_numeric {
63            write!(f, " [{:02x}{:02x}]", self.cfg.base_class, self.cfg.sub_class)?;
64        }
65        write!(f, ":")?;
66
67        if let Some(name) = &self.name {
68            if !self.args.only_print_numeric {
69                write!(f, " {}", name)?;
70            }
71        }
72
73        if self.name.is_none() || self.args.print_numeric || self.args.only_print_numeric {
74            write!(f, " [{:04x}:{:04x}]", { self.cfg.vendor_id }, { self.cfg.device_id })?;
75        }
76        writeln!(f, " (rev {:02x})", self.cfg.revision_id)?;
77        if self.args.verbose {
78            writeln!(f, "\tControl: {}", CommandRegister(self.cfg.command))?;
79            writeln!(f, "\tStatus: {}", StatusRegister(self.cfg.status))?;
80        };
81
82        Ok(())
83    }
84
85    pub fn print_common_footer(&self, f: &'a mut fmt::Formatter<'_>) -> fmt::Result {
86        if self.args.verbose {
87            for bar in &self.device.base_addresses {
88                if bar.size > 0 {
89                    write!(f, "\t{}", BaseAddress(bar))?;
90                }
91            }
92            for capability in &self.device.capabilities {
93                writeln!(f, "\t{}", Capability::new(capability, &self.device.config[..]))?;
94            }
95            for ext_capability in &self.device.ext_capabilities {
96                writeln!(f, "\t{}", ExtendedCapability::new(ext_capability))?;
97            }
98        }
99
100        if self.args.print_config {
101            write!(
102                f,
103                "{}",
104                Hexdumper {
105                    bytes: &self.device.config,
106                    show_header: true,
107                    show_ascii: false,
108                    offset: None
109                }
110            )?;
111        }
112
113        if self.args.verbose || self.args.print_config {
114            writeln!(f)?;
115        }
116
117        Ok(())
118    }
119}
120
121impl<'a> fmt::Display for Device<'a> {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        self.print_common_header(f)?;
124        self.print_common_footer(f)?;
125        Ok(())
126    }
127}