git: 46d383af0dbd - main - pciconf: Add -C option to filter by class name

From: Bojan Novković <bnovkov_at_FreeBSD.org>
Date: Mon, 21 Sep 2026 18:39:35 UTC
The branch main has been updated by bnovkov:

URL: https://cgit.FreeBSD.org/src/commit/?id=46d383af0dbdb3871354f344b9c1ba99da691121

commit 46d383af0dbdb3871354f344b9c1ba99da691121
Author:     Federico Angelilli <code@fedang.net>
AuthorDate: 2026-09-21 18:23:10 +0000
Commit:     Bojan Novković <bnovkov@FreeBSD.org>
CommitDate: 2026-09-21 18:37:59 +0000

    pciconf: Add -C option to filter by class name
    
    Differential Revision:  https://reviews.freebsd.org/D59602
    MFC after:      3 weeks
    PR:             289923
    Reviewed by:    bnovkov
---
 usr.sbin/pciconf/pciconf.8 | 10 ++++++++--
 usr.sbin/pciconf/pciconf.c | 40 +++++++++++++++++++++++++++++++++++-----
 2 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/usr.sbin/pciconf/pciconf.8 b/usr.sbin/pciconf/pciconf.8
index 1c9be4e817ae..e82db4ed0fc8 100644
--- a/usr.sbin/pciconf/pciconf.8
+++ b/usr.sbin/pciconf/pciconf.8
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 5, 2026
+.Dd September 21, 2026
 .Dt PCICONF 8
 .Os
 .Sh NAME
@@ -31,7 +31,7 @@
 .Nd diagnostic utility for the PCI bus
 .Sh SYNOPSIS
 .Nm
-.Fl l Oo Fl BbceVv Oc Op Ar device
+.Fl l Oo Fl BbceVv Oc Oo Fl C Ar class Oc Op Ar device
 .Nm
 .Fl t Oo Fl v Oc
 .Nm
@@ -227,6 +227,12 @@ Each capability is enumerated via a line in the following format:
     cap 10[40] = PCI-Express 1 root port
 .Ed
 .Pp
+If the
+.Fl C
+option is supplied,
+.Nm
+will list only the devices whose PCI class name matches the given argument.
+.Pp
 The first value after the
 .Dq Li cap
 prefix is the capability ID in hexadecimal.
diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c
index 581a0cb3ff85..7da61da5fa11 100644
--- a/usr.sbin/pciconf/pciconf.c
+++ b/usr.sbin/pciconf/pciconf.c
@@ -79,10 +79,11 @@ static struct pcisel getsel(const char *str);
 static void list_bridge(int fd, struct pci_conf *p);
 static void list_bars(int fd, struct pci_conf *p);
 static void list_devs(const char *name, int verbose, int bars, int bridge,
-    int caps, int errors, int vpd, int compact);
+    int caps, int errors, int vpd, int compact, const char *class);
 static void show_tree(int verbose);
 static void list_verbose(struct pci_conf *p);
 static void list_vpd(int fd, struct pci_conf *p);
+static bool validate_class(const char *class);
 static const char *guess_class(struct pci_conf *p);
 static const char *guess_subclass(struct pci_conf *p);
 static int load_vendors(void);
@@ -103,7 +104,7 @@ usage(void)
 {
 
 	fprintf(stderr, "%s",
-		"usage: pciconf -l [-BbcevV] [device]\n"
+		"usage: pciconf -l [-BbcevV] [-C class] [device]\n"
 		"       pciconf -t [-v]\n"
 		"       pciconf -a device\n"
 		"       pciconf -r [-b | -h] device addr[:addr2]\n"
@@ -122,12 +123,14 @@ main(int argc, char **argv)
 	enum { NONE, LIST, TREE, READ, WRITE, ATTACHED, DUMPBAR, READBAR,
 	    WRITEBAR } mode;
 	int compact, bars, bridge, caps, errors, verbose, vpd;
+	const char *class;
 
 	mode = NONE;
 	compact = bars = bridge = caps = errors = verbose = vpd = 0;
 	width = 4;
+	class = NULL;
 
-	while ((c = getopt(argc, argv, "aBbcDehlRrtWwVvx")) != -1) {
+	while ((c = getopt(argc, argv, "aBbcC:DehlRrtWwVvx")) != -1) {
 		switch(c) {
 		case 'a':
 			mode = ATTACHED;
@@ -146,6 +149,10 @@ main(int argc, char **argv)
 			caps++;
 			break;
 
+		case 'C':
+			class = optarg;
+			break;
+
 		case 'D':
 			mode = DUMPBAR;
 			break;
@@ -206,7 +213,7 @@ main(int argc, char **argv)
 		if (optind >= argc + 1)
 			usage();
 		list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose,
-		    bars, bridge, caps, errors, vpd, compact);
+		    bars, bridge, caps, errors, vpd, compact, class);
 		break;
 	case TREE:
 		if (optind != argc)
@@ -314,16 +321,20 @@ fetch_devs(int fd, const char *name, struct pci_conf **confp, size_t *countp)
 
 static void
 list_devs(const char *name, int verbose, int bars, int bridge, int caps,
-    int errors, int vpd, int compact)
+    int errors, int vpd, int compact, const char *class)
 {
 	int fd;
 	struct pci_conf *conf, *p;
 	size_t count;
+	const char *pclass;
 	int none_count = 0;
 
 	if (verbose)
 		load_vendors();
 
+	if (class != NULL && !validate_class(class))
+		errx(1, "Invalid class name");
+
 	fd = open(_PATH_DEVPCI, (bridge || caps || errors) ? O_RDWR : O_RDONLY,
 	    0);
 	if (fd < 0)
@@ -339,6 +350,12 @@ list_devs(const char *name, int verbose, int bars, int bridge, int caps,
 		printf("drv\tselector\tclass    rev  hdr  "
 		    "vendor device subven subdev\n");
 	for (p = conf; p < conf + count; p++) {
+		if (class != NULL) {
+			pclass = guess_class(p);
+			if (pclass == NULL || strcasecmp(pclass, class) != 0)
+				continue;
+		}
+
 		if (compact)
 			printf("%s%d@pci%d:%d:%d:%d:"
 			    "\t%06x   %02x   %02x   "
@@ -1081,6 +1098,19 @@ static struct
 	{0, 0,		NULL}
 };
 
+static bool
+validate_class(const char *class)
+{
+	int i;
+
+	for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) {
+		if ((strcasecmp(class, pci_nomatch_tab[i].desc) == 0) &&
+		    (pci_nomatch_tab[i].subclass == -1))
+			return (true);
+	}
+	return (false);
+}
+
 static const char *
 guess_class(struct pci_conf *p)
 {