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::capability::Capability;
5use crate::config::{CommandRegister, StatusRegister, Type00Config};
6use crate::db::PciDb;
7use crate::util::{format_bytes, Hexdumper};
8use crate::Args;
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        }
96
97        if self.args.print_config {
98            write!(
99                f,
100                "{}",
101                Hexdumper {
102                    bytes: &self.device.config,
103                    show_header: true,
104                    show_ascii: false,
105                    offset: None
106                }
107            )?;
108        }
109
110        if self.args.verbose || self.args.print_config {
111            writeln!(f)?;
112        }
113
114        Ok(())
115    }
116}
117
118impl<'a> fmt::Display for Device<'a> {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        self.print_common_header(f)?;
121        self.print_common_footer(f)?;
122        Ok(())
123    }
124}