1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
23 * Copyright 2021 Oxide Computer Company
24 */
25
26 /*
27 * This library exists to understand and parse the pci.ids database that is
28 * maintained at http://pci-ids.ucw.cz/ and in the gate at cmd/hwdata. This
29 * database provides a way to map the PCI device, vendor, and subsystem ids to
30 * a human understandable name.
31 *
32 * This library exports this data in a similar way to a tree. The handle that
33 * is returned from pcidb_open is the root of the tree. The next level are the
34 * vendors. Each vendor has a unique set of devices and each device has a unique
35 * set of subvendor and subdevice pairs.
36 *
37 * Parsing information:
38 *
39 * The database is formatted in the following basic format:
40 * vendor_id<two spaces>vendor_name
41 * <tab>device_id<two spaces>device_name
42 * <tab><tab>subvendor<space>subdevice<two spaces>subsystem_name
43 *
44 * For any given vendor, there can be multiple devices. And for any given device
45 * there will be multiple subsystems. In addition, there can be comments that
46 * start a line which use the '#' character.
47 *
48 * At the end of the file, there are a series of PCI classes. Those will start
49 * with a single C<space>. Once we hit those, we stop all parsing. We currently
50 * don't care about consuming or presenting those.
51 */
52
53 #include <sys/types.h>
54 #include <stdint.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <errno.h>
58 #include <string.h>
59 #include <assert.h>
60 #include <unistd.h>
61 #include <stddef.h>
62 #include <sys/list.h>
63
64 #include "pcidb.h"
65
66 #define PCI_NAME_MAX 256
67 #define PCI_READLINE 1024
68
69 struct pcidb_progif {
70 char pp_name[PCI_NAME_MAX];
71 list_node_t pp_link;
72 pcidb_subclass_t *pp_subclass;
73 uint8_t pp_code;
74 };
75
76 struct pcidb_subclass {
77 char psc_name[PCI_NAME_MAX];
78 list_node_t psc_link;
79 list_t psc_progifs;
80 pcidb_class_t *psc_class;
81 uint8_t psc_code;
82 };
83
84 struct pcidb_class {
85 char pc_name[PCI_NAME_MAX];
86 list_node_t pc_link;
87 list_t pc_subclass;
88 pcidb_hdl_t *pc_hdl;
89 uint8_t pc_code;
90 };
91
92 struct pcidb_subvd {
93 uint16_t ps_vid;
94 uint16_t ps_did;
95 char ps_name[PCI_NAME_MAX];
96 list_node_t ps_link;
97 pcidb_device_t *ps_dev;
98 pcidb_vendor_t *ps_vend;
99 };
100
101 struct pcidb_device {
102 uint16_t pd_id;
103 char pd_name[PCI_NAME_MAX];
104 list_t pd_subs;
105 list_node_t pd_link;
106 pcidb_vendor_t *pd_vend;
107 };
108
109 struct pcidb_vendor {
110 uint16_t pv_id;
111 char pv_name[PCI_NAME_MAX];
112 list_t pv_devs;
113 list_node_t pv_link;
114 pcidb_hdl_t *pv_hdl;
115 };
116
117 struct pcidb_hdl {
118 list_t ph_vendors;
119 list_t ph_classes;
120 };
121
122 typedef enum pcidb_parse {
123 PDB_INIT,
124 PDB_VENDOR,
125 PDB_DEVICE,
126 PDB_SUBDEV,
127 PDB_CLASS,
128 PDB_SUBCLASS,
129 PDB_PROGIF
130 } pcidb_parse_t;
131
132 static const char *pci_db = "/usr/share/hwdata/pci.ids";
133
134 static pcidb_vendor_t *
parse_vendor(char * buf,pcidb_hdl_t * hdl)135 parse_vendor(char *buf, pcidb_hdl_t *hdl)
136 {
137 pcidb_vendor_t *vend;
138
139 vend = malloc(sizeof (pcidb_vendor_t));
140 if (vend == NULL)
141 return (NULL);
142
143 list_create(&vend->pv_devs, sizeof (pcidb_device_t),
144 offsetof(pcidb_device_t, pd_link));
145 vend->pv_hdl = hdl;
146 list_insert_tail(&hdl->ph_vendors, vend);
147
148 buf[4] = '\0';
149 vend->pv_id = strtol(buf, NULL, 16);
150 buf += 6;
151
152 (void) strlcpy(vend->pv_name, buf, PCI_NAME_MAX);
153
154 return (vend);
155 }
156
157 static pcidb_device_t *
parse_device(char * buf,pcidb_vendor_t * vend)158 parse_device(char *buf, pcidb_vendor_t *vend)
159 {
160 pcidb_device_t *dev;
161
162 dev = malloc(sizeof (pcidb_device_t));
163 if (dev == NULL)
164 return (dev);
165
166 list_create(&dev->pd_subs, sizeof (pcidb_subvd_t),
167 offsetof(pcidb_subvd_t, ps_link));
168 dev->pd_vend = vend;
169 list_insert_tail(&vend->pv_devs, dev);
170
171 buf++;
172 buf[4] = '\0';
173 dev->pd_id = strtol(buf, NULL, 16);
174 buf += 6;
175
176 (void) strlcpy(dev->pd_name, buf, PCI_NAME_MAX);
177 return (dev);
178 }
179
180 static pcidb_subvd_t *
parse_subdev(char * buf,pcidb_device_t * dev)181 parse_subdev(char *buf, pcidb_device_t *dev)
182 {
183 pcidb_subvd_t *sub;
184
185 sub = malloc(sizeof (pcidb_subvd_t));
186 if (sub == NULL)
187 return (NULL);
188
189 sub->ps_dev = dev;
190 sub->ps_vend = dev->pd_vend;
191 list_insert_tail(&dev->pd_subs, sub);
192
193 buf += 2;
194 buf[4] = '\0';
195 sub->ps_vid = strtol(buf, NULL, 16);
196 buf += 5;
197 buf[4] = '\0';
198 sub->ps_did = strtol(buf, NULL, 16);
199 buf += 6;
200
201 (void) strlcpy(sub->ps_name, buf, PCI_NAME_MAX);
202
203 return (sub);
204 }
205
206 static pcidb_class_t *
pcidb_parse_class(char * buf,pcidb_hdl_t * hdl)207 pcidb_parse_class(char *buf, pcidb_hdl_t *hdl)
208 {
209 pcidb_class_t *class;
210
211 class = malloc(sizeof (pcidb_class_t));
212 if (class == NULL)
213 return (NULL);
214
215 list_create(&class->pc_subclass, sizeof (pcidb_subclass_t),
216 offsetof(pcidb_subclass_t, psc_link));
217 class->pc_hdl = hdl;
218 list_insert_tail(&hdl->ph_classes, class);
219
220 buf += 2;
221 buf[3] = '\0';
222 class->pc_code = strtol(buf, NULL, 16);
223 buf += 4;
224 (void) strlcpy(class->pc_name, buf, PCI_NAME_MAX);
225
226 return (class);
227 }
228
229 static pcidb_subclass_t *
pcidb_parse_subclass(char * buf,pcidb_class_t * class)230 pcidb_parse_subclass(char *buf, pcidb_class_t *class)
231 {
232 pcidb_subclass_t *sub;
233
234 sub = malloc(sizeof (pcidb_subclass_t));
235 if (sub == NULL)
236 return (NULL);
237
238 list_create(&sub->psc_progifs, sizeof (pcidb_progif_t),
239 offsetof(pcidb_progif_t, pp_link));
240 sub->psc_class = class;
241 list_insert_tail(&class->pc_subclass, sub);
242
243 buf++;
244 buf[3] = '\0';
245 sub->psc_code = strtol(buf, NULL, 16);
246 buf += 4;
247 (void) strlcpy(sub->psc_name, buf, PCI_NAME_MAX);
248
249 return (sub);
250 }
251
252 static pcidb_progif_t *
pcidb_parse_progif(char * buf,pcidb_subclass_t * sub)253 pcidb_parse_progif(char *buf, pcidb_subclass_t *sub)
254 {
255 pcidb_progif_t *prog;
256
257 prog = malloc(sizeof (pcidb_progif_t));
258 if (prog == NULL) {
259 return (NULL);
260 }
261
262 prog->pp_subclass = sub;
263 list_insert_tail(&sub->psc_progifs, prog);
264
265 buf += 2;
266 buf[3] = '\0';
267 prog->pp_code = strtol(buf, NULL, 16);
268 buf += 4;
269 (void) strlcpy(prog->pp_name, buf, PCI_NAME_MAX);
270
271 return (prog);
272 }
273
274 static int
readline(FILE * f,char * buf,size_t len)275 readline(FILE *f, char *buf, size_t len)
276 {
277 for (;;) {
278 char *c;
279
280 if (fgets(buf, len, f) == NULL)
281 return (-1);
282
283 if ((c = strchr(buf, '\n')) != NULL)
284 *c = '\0';
285
286 if (buf[0] != '#' && buf[0] != '\0')
287 return (0);
288 }
289 }
290
291 static int
parse_db(FILE * f,pcidb_hdl_t * hdl)292 parse_db(FILE *f, pcidb_hdl_t *hdl)
293 {
294 pcidb_vendor_t *vend = NULL;
295 pcidb_device_t *dev = NULL;
296 pcidb_class_t *class = NULL;
297 pcidb_subclass_t *sub = NULL;
298 pcidb_parse_t state = PDB_INIT;
299
300 for (;;) {
301 char buf[1024];
302
303 errno = 0;
304 if (readline(f, buf, sizeof (buf)) != 0) {
305 if (errno != 0)
306 return (-1);
307 else
308 return (0);
309 }
310
311 newstate:
312 switch (state) {
313 case PDB_INIT:
314 vend = NULL;
315 dev = NULL;
316 class = NULL;
317 sub = NULL;
318 if (buf[0] == 'C') {
319 state = PDB_CLASS;
320 } else {
321 state = PDB_VENDOR;
322 }
323 goto newstate;
324 case PDB_VENDOR:
325 vend = parse_vendor(buf, hdl);
326 if (vend == NULL)
327 return (-1);
328 state = PDB_DEVICE;
329 break;
330 case PDB_DEVICE:
331 if (buf[0] != '\t') {
332 state = PDB_INIT;
333 goto newstate;
334 }
335
336 if (buf[1] == '\t') {
337 state = PDB_SUBDEV;
338 goto newstate;
339 }
340
341 assert(vend != NULL);
342 dev = parse_device(buf, vend);
343 if (dev == NULL)
344 return (0);
345 break;
346 case PDB_SUBDEV:
347 if (buf[0] != '\t') {
348 state = PDB_INIT;
349 goto newstate;
350 }
351
352 if (buf[0] == '\t' && buf[1] != '\t') {
353 state = PDB_DEVICE;
354 goto newstate;
355 }
356
357 assert(buf[0] == '\t' && buf[1] == '\t');
358 assert(dev != NULL);
359 if (parse_subdev(buf, dev) == NULL) {
360 return (-1);
361 }
362 break;
363 case PDB_CLASS:
364 class = pcidb_parse_class(buf, hdl);
365 state = PDB_SUBCLASS;
366 break;
367 case PDB_SUBCLASS:
368 if (buf[0] != '\t') {
369 state = PDB_INIT;
370 goto newstate;
371 }
372
373 if (buf[1] == '\t') {
374 state = PDB_PROGIF;
375 goto newstate;
376 }
377
378 assert(class != NULL);
379 sub = pcidb_parse_subclass(buf, class);
380 if (sub == NULL) {
381 return (-1);
382 }
383 break;
384 case PDB_PROGIF:
385 if (buf[0] != '\t') {
386 state = PDB_INIT;
387 goto newstate;
388 }
389
390 if (buf[0] == '\t' && buf[1] != '\t') {
391 state = PDB_SUBCLASS;
392 goto newstate;
393 }
394
395 assert(sub != NULL);
396 if (pcidb_parse_progif(buf, sub) == NULL) {
397 return (-1);
398 }
399 break;
400 }
401 }
402 }
403
404 pcidb_hdl_t *
pcidb_open(int version)405 pcidb_open(int version)
406 {
407 pcidb_hdl_t *h;
408 FILE *f;
409
410 if (version != PCIDB_VERSION) {
411 errno = EINVAL;
412 return (NULL);
413 }
414
415 h = malloc(sizeof (pcidb_hdl_t));
416 if (h == NULL)
417 return (NULL);
418
419 list_create(&h->ph_vendors, sizeof (pcidb_vendor_t),
420 offsetof(pcidb_vendor_t, pv_link));
421 list_create(&h->ph_classes, sizeof (pcidb_class_t),
422 offsetof(pcidb_class_t, pc_link));
423
424 f = fopen(pci_db, "rF");
425 if (f == NULL) {
426 free(h);
427 return (NULL);
428 }
429
430 if (parse_db(f, h) < 0) {
431 (void) fclose(f);
432 pcidb_close(h);
433 return (NULL);
434 }
435
436 (void) fclose(f);
437
438 return (h);
439 }
440
441 void
pcidb_close(pcidb_hdl_t * hdl)442 pcidb_close(pcidb_hdl_t *hdl)
443 {
444 pcidb_vendor_t *vend;
445 pcidb_class_t *class;
446
447 if (hdl == NULL)
448 return;
449
450 while ((vend = list_remove_head(&hdl->ph_vendors)) != NULL) {
451 pcidb_device_t *dev;
452
453 while ((dev = list_remove_head(&vend->pv_devs)) != NULL) {
454 pcidb_subvd_t *sub;
455
456 while ((sub = list_remove_head(&dev->pd_subs)) !=
457 NULL) {
458 free(sub);
459 }
460 list_destroy(&dev->pd_subs);
461 free(dev);
462 }
463 list_destroy(&vend->pv_devs);
464 free(vend);
465 }
466 list_destroy(&hdl->ph_vendors);
467
468 while ((class = list_remove_head(&hdl->ph_classes)) != NULL) {
469 pcidb_subclass_t *sub;
470
471 while ((sub = list_remove_head(&class->pc_subclass)) != NULL) {
472 pcidb_progif_t *prog;
473
474 while ((prog = list_remove_head(&sub->psc_progifs)) !=
475 NULL) {
476 free(prog);
477 }
478 list_destroy(&sub->psc_progifs);
479 free(sub);
480 }
481 list_destroy(&class->pc_subclass);
482 free(class);
483 }
484 list_destroy(&hdl->ph_classes);
485
486 free(hdl);
487 }
488
489 pcidb_vendor_t *
pcidb_lookup_vendor(pcidb_hdl_t * hdl,uint16_t id)490 pcidb_lookup_vendor(pcidb_hdl_t *hdl, uint16_t id)
491 {
492 pcidb_vendor_t *v;
493
494 for (v = list_head(&hdl->ph_vendors); v != NULL;
495 v = list_next(&hdl->ph_vendors, v)) {
496 if (v->pv_id == id)
497 return (v);
498 }
499
500 return (NULL);
501 }
502
503 const char *
pcidb_vendor_name(pcidb_vendor_t * vend)504 pcidb_vendor_name(pcidb_vendor_t *vend)
505 {
506 return (vend->pv_name);
507 }
508
509 uint16_t
pcidb_vendor_id(pcidb_vendor_t * vend)510 pcidb_vendor_id(pcidb_vendor_t *vend)
511 {
512 return (vend->pv_id);
513 }
514
515 pcidb_vendor_t *
pcidb_vendor_iter(pcidb_hdl_t * hdl)516 pcidb_vendor_iter(pcidb_hdl_t *hdl)
517 {
518 return (list_head(&hdl->ph_vendors));
519 }
520
521 pcidb_vendor_t *
pcidb_vendor_iter_next(pcidb_vendor_t * vend)522 pcidb_vendor_iter_next(pcidb_vendor_t *vend)
523 {
524 assert(vend != NULL);
525 return (list_next(&vend->pv_hdl->ph_vendors, vend));
526 }
527
528 pcidb_device_t *
pcidb_lookup_device_by_vendor(pcidb_vendor_t * vend,uint16_t id)529 pcidb_lookup_device_by_vendor(pcidb_vendor_t *vend, uint16_t id)
530 {
531 assert(vend != NULL);
532
533 for (pcidb_device_t *dev = list_head(&vend->pv_devs); dev != NULL;
534 dev = list_next(&vend->pv_devs, dev)) {
535 if (dev->pd_id == id)
536 return (dev);
537 }
538
539 return (NULL);
540 }
541
542 pcidb_device_t *
pcidb_lookup_device(pcidb_hdl_t * hdl,uint16_t vid,uint16_t did)543 pcidb_lookup_device(pcidb_hdl_t *hdl, uint16_t vid, uint16_t did)
544 {
545 pcidb_vendor_t *vend;
546
547 vend = pcidb_lookup_vendor(hdl, vid);
548 if (vend == NULL)
549 return (NULL);
550
551 return (pcidb_lookup_device_by_vendor(vend, did));
552 }
553
554 pcidb_device_t *
pcidb_device_iter(pcidb_vendor_t * vend)555 pcidb_device_iter(pcidb_vendor_t *vend)
556 {
557 return (list_head(&vend->pv_devs));
558 }
559
560 pcidb_device_t *
pcidb_device_iter_next(pcidb_device_t * dev)561 pcidb_device_iter_next(pcidb_device_t *dev)
562 {
563 return (list_next(&dev->pd_vend->pv_devs, dev));
564 }
565
566 const char *
pcidb_device_name(pcidb_device_t * dev)567 pcidb_device_name(pcidb_device_t *dev)
568 {
569 return (dev->pd_name);
570 }
571
572 uint16_t
pcidb_device_id(pcidb_device_t * dev)573 pcidb_device_id(pcidb_device_t *dev)
574 {
575 return (dev->pd_id);
576 }
577
578 pcidb_vendor_t *
pcidb_device_vendor(pcidb_device_t * dev)579 pcidb_device_vendor(pcidb_device_t *dev)
580 {
581 return (dev->pd_vend);
582 }
583
584 pcidb_subvd_t *
pcidb_lookup_subvd_by_device(pcidb_device_t * dev,uint16_t svid,uint16_t sdid)585 pcidb_lookup_subvd_by_device(pcidb_device_t *dev, uint16_t svid, uint16_t sdid)
586 {
587 pcidb_subvd_t *sub;
588
589 assert(dev != NULL);
590
591 for (sub = list_head(&dev->pd_subs); sub != NULL;
592 sub = list_next(&dev->pd_subs, sub)) {
593 if (sub->ps_vid == svid && sub->ps_did == sdid)
594 return (sub);
595 }
596
597 return (NULL);
598 }
599
600 pcidb_subvd_t *
pcidb_lookup_subvd_by_vendor(pcidb_vendor_t * vend,uint16_t devid,uint16_t svid,uint16_t sdid)601 pcidb_lookup_subvd_by_vendor(pcidb_vendor_t *vend, uint16_t devid,
602 uint16_t svid, uint16_t sdid)
603 {
604 pcidb_device_t *dev;
605
606 assert(vend != NULL);
607 dev = pcidb_lookup_device_by_vendor(vend, devid);
608 if (dev == NULL)
609 return (NULL);
610
611 return (pcidb_lookup_subvd_by_device(dev, svid, sdid));
612 }
613
614 pcidb_subvd_t *
pcidb_lookup_subvd(pcidb_hdl_t * hdl,uint16_t vid,uint16_t did,uint16_t svid,uint16_t sdid)615 pcidb_lookup_subvd(pcidb_hdl_t *hdl, uint16_t vid, uint16_t did, uint16_t svid,
616 uint16_t sdid)
617 {
618 pcidb_device_t *dev;
619
620 assert(hdl != NULL);
621 dev = pcidb_lookup_device(hdl, vid, did);
622 if (dev == NULL)
623 return (NULL);
624
625 return (pcidb_lookup_subvd_by_device(dev, svid, sdid));
626 }
627
628 pcidb_subvd_t *
pcidb_subvd_iter(pcidb_device_t * dev)629 pcidb_subvd_iter(pcidb_device_t *dev)
630 {
631 return (list_head(&dev->pd_subs));
632 }
633
634 pcidb_subvd_t *
pcidb_subvd_iter_next(pcidb_subvd_t * sub)635 pcidb_subvd_iter_next(pcidb_subvd_t *sub)
636 {
637 return (list_next(&sub->ps_dev->pd_subs, sub));
638 }
639
640 const char *
pcidb_subvd_name(pcidb_subvd_t * sub)641 pcidb_subvd_name(pcidb_subvd_t *sub)
642 {
643 return (sub->ps_name);
644 }
645
646 uint16_t
pcidb_subvd_svid(pcidb_subvd_t * sub)647 pcidb_subvd_svid(pcidb_subvd_t *sub)
648 {
649 return (sub->ps_vid);
650 }
651
652 uint16_t
pcidb_subvd_sdid(pcidb_subvd_t * sub)653 pcidb_subvd_sdid(pcidb_subvd_t *sub)
654 {
655 return (sub->ps_did);
656 }
657
658 pcidb_device_t *
pcidb_subvd_device(pcidb_subvd_t * sub)659 pcidb_subvd_device(pcidb_subvd_t *sub)
660 {
661 return (sub->ps_dev);
662 }
663
664 pcidb_vendor_t *
pcidb_subvd_vendor(pcidb_subvd_t * sub)665 pcidb_subvd_vendor(pcidb_subvd_t *sub)
666 {
667 return (sub->ps_vend);
668 }
669
670
671 pcidb_class_t *
pcidb_lookup_class(pcidb_hdl_t * hdl,uint8_t code)672 pcidb_lookup_class(pcidb_hdl_t *hdl, uint8_t code)
673 {
674 for (pcidb_class_t *class = list_head(&hdl->ph_classes); class != NULL;
675 class = list_next(&hdl->ph_classes, class)) {
676 if (class->pc_code == code) {
677 return (class);
678 }
679 }
680
681 return (NULL);
682 }
683
684 pcidb_class_t *
pcidb_class_iter(pcidb_hdl_t * hdl)685 pcidb_class_iter(pcidb_hdl_t *hdl)
686 {
687 return (list_head(&hdl->ph_classes));
688 }
689
690 pcidb_class_t *
pcidb_class_iter_next(pcidb_class_t * class)691 pcidb_class_iter_next(pcidb_class_t *class)
692 {
693 return (list_next(&class->pc_hdl->ph_classes, class));
694 }
695
696 const char *
pcidb_class_name(pcidb_class_t * class)697 pcidb_class_name(pcidb_class_t *class)
698 {
699 return (class->pc_name);
700 }
701
702 uint8_t
pcidb_class_code(pcidb_class_t * class)703 pcidb_class_code(pcidb_class_t *class)
704 {
705 return (class->pc_code);
706 }
707
708 pcidb_subclass_t *
pcidb_lookup_subclass(pcidb_hdl_t * hdl,uint8_t ccode,uint8_t subcode)709 pcidb_lookup_subclass(pcidb_hdl_t *hdl, uint8_t ccode, uint8_t subcode)
710 {
711 pcidb_class_t *class;
712
713 class = pcidb_lookup_class(hdl, ccode);
714 if (class == NULL) {
715 return (NULL);
716 }
717
718 return (pcidb_lookup_subclass_by_class(class, subcode));
719 }
720
721 pcidb_subclass_t *
pcidb_lookup_subclass_by_class(pcidb_class_t * class,uint8_t code)722 pcidb_lookup_subclass_by_class(pcidb_class_t *class, uint8_t code)
723 {
724 for (pcidb_subclass_t *sub = list_head(&class->pc_subclass);
725 sub != NULL; sub = list_next(&class->pc_subclass, sub)) {
726 if (sub->psc_code == code) {
727 return (sub);
728 }
729 }
730
731 return (NULL);
732 }
733
734 pcidb_subclass_t *
pcidb_subclass_iter(pcidb_class_t * class)735 pcidb_subclass_iter(pcidb_class_t *class)
736 {
737 return (list_head(&class->pc_subclass));
738 }
739
740 pcidb_subclass_t *
pcidb_subclass_iter_next(pcidb_subclass_t * sub)741 pcidb_subclass_iter_next(pcidb_subclass_t *sub)
742 {
743 return (list_next(&sub->psc_class->pc_subclass, sub));
744 }
745
746 const char *
pcidb_subclass_name(pcidb_subclass_t * sub)747 pcidb_subclass_name(pcidb_subclass_t *sub)
748 {
749 return (sub->psc_name);
750 }
751
752 uint8_t
pcidb_subclass_code(pcidb_subclass_t * sub)753 pcidb_subclass_code(pcidb_subclass_t *sub)
754 {
755 return (sub->psc_code);
756 }
757
758 pcidb_progif_t *
pcidb_lookup_progif(pcidb_hdl_t * hdl,uint8_t ccode,uint8_t scode,uint8_t pcode)759 pcidb_lookup_progif(pcidb_hdl_t *hdl, uint8_t ccode, uint8_t scode,
760 uint8_t pcode)
761 {
762 pcidb_subclass_t *sub;
763
764 sub = pcidb_lookup_subclass(hdl, ccode, scode);
765 if (sub == NULL) {
766 return (NULL);
767 }
768
769 return (pcidb_lookup_progif_by_subclass(sub, pcode));
770 }
771
772 pcidb_progif_t *
pcidb_lookup_progif_by_subclass(pcidb_subclass_t * sub,uint8_t code)773 pcidb_lookup_progif_by_subclass(pcidb_subclass_t *sub, uint8_t code)
774 {
775 for (pcidb_progif_t *prog = list_head(&sub->psc_progifs); prog != NULL;
776 prog = list_next(&sub->psc_progifs, prog)) {
777 if (prog->pp_code == code) {
778 return (prog);
779 }
780 }
781
782 return (NULL);
783 }
784
785 pcidb_progif_t *
pcidb_progif_iter(pcidb_subclass_t * sub)786 pcidb_progif_iter(pcidb_subclass_t *sub)
787 {
788 return (list_head(&sub->psc_progifs));
789 }
790
791 pcidb_progif_t *
pcidb_progif_iter_next(pcidb_progif_t * prog)792 pcidb_progif_iter_next(pcidb_progif_t *prog)
793 {
794 return (list_next(&prog->pp_subclass->psc_progifs, prog));
795 }
796
797 const char *
pcidb_progif_name(pcidb_progif_t * prog)798 pcidb_progif_name(pcidb_progif_t *prog)
799 {
800 return (prog->pp_name);
801 }
802
803 uint8_t
pcidb_progif_code(pcidb_progif_t * prog)804 pcidb_progif_code(pcidb_progif_t *prog)
805 {
806 return (prog->pp_code);
807 }
808