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.
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.
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]
22 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 * This library exists to understand and parse the pci.ids database that is
27 * maintained at http://pci-ids.ucw.cz/ and in the gate at cmd/hwdata. This
28 * database provides a way to map the PCI device, vendor, and subsystem ids to
29 * a human understandable name.
31 * This library exports this data in a similar way to a tree. The handle that
32 * is returned from pcidb_open is the root of the tree. The next level are the
33 * vendors. Each vendor has a unique set of devices and each device has a unique
34 * set of subvendor and subdevice pairs.
36 * Parsing information:
38 * The database is formatted in the following basic format:
39 * vendor_id<two spaces>vendor_name
40 * <tab>device_id<two spaces>device_name
41 * <tab><tab>subvendor<space>subdevice<two spaces>subsystem_name
43 * For any given vendor, there can be multiple devices. And for any given device
44 * there will be multiple subsystems. In addition, there can be comments that
45 * start a line which use the '#' character.
47 * At the end of the file, there are a series of PCI classes. Those will start
48 * with a single C<space>. Once we hit those, we stop all parsing. We currently
49 * don't care about consuming or presenting those.
52 #include <sys/types.h>
63 #define PCI_NAME_MAX 256
64 #define PCI_READLINE 1024
66 /* Forward declarations */
74 char ps_name
[PCI_NAME_MAX
];
75 struct pcidb_subvd
*ps_prev
;
76 struct pcidb_subvd
*ps_next
;
77 struct pcidb_device
*ps_dev
;
78 struct pcidb_vendor
*ps_vend
;
83 char pd_name
[PCI_NAME_MAX
];
84 struct pcidb_subvd
*pd_sstart
;
85 struct pcidb_subvd
*pd_send
;
86 struct pcidb_device
*pd_next
;
87 struct pcidb_device
*pd_prev
;
88 struct pcidb_vendor
*pd_vend
;
93 char pv_name
[PCI_NAME_MAX
];
94 struct pcidb_device
*pv_dstart
;
95 struct pcidb_device
*pv_dend
;
96 struct pcidb_vendor
*pv_prev
;
97 struct pcidb_vendor
*pv_next
;
101 pcidb_vendor_t
*ph_vstart
;
102 pcidb_vendor_t
*ph_vend
;
105 typedef enum pcidb_parse
{
111 static const char *pci_db
= "/usr/share/hwdata/pci.ids";
114 pcihdl_add_vendor(pcidb_hdl_t
*hdl
, pcidb_vendor_t
*v
)
116 if (hdl
->ph_vstart
== NULL
&& hdl
->ph_vend
== NULL
) {
122 v
->pv_prev
= hdl
->ph_vend
;
124 hdl
->ph_vend
->pv_next
= v
;
129 static pcidb_vendor_t
*
130 parse_vendor(char *buf
, pcidb_hdl_t
*hdl
)
135 v
= malloc(sizeof (pcidb_vendor_t
));
139 pcihdl_add_vendor(hdl
, v
);
144 v
->pv_id
= strtol(buf
, NULL
, 16);
147 if (buf
[len
-1] == '\n')
150 (void) strlcpy(v
->pv_name
, buf
, PCI_NAME_MAX
);
156 insert_device(pcidb_vendor_t
*v
, pcidb_device_t
*d
)
159 if (v
->pv_dstart
== NULL
&& v
->pv_dend
== NULL
) {
165 d
->pd_prev
= v
->pv_dend
;
167 v
->pv_dend
->pd_next
= d
;
172 static pcidb_device_t
*
173 parse_device(char *buf
, pcidb_vendor_t
*v
)
178 d
= malloc(sizeof (pcidb_device_t
));
188 d
->pd_id
= strtol(buf
, NULL
, 16);
191 if (buf
[len
-1] == '\n')
194 (void) strlcpy(d
->pd_name
, buf
, PCI_NAME_MAX
);
199 insert_subdev(pcidb_device_t
*d
, pcidb_subvd_t
*s
)
202 s
->ps_vend
= d
->pd_vend
;
203 if (d
->pd_sstart
== NULL
) {
209 s
->ps_prev
= d
->pd_send
;
211 d
->pd_send
->ps_next
= s
;
216 static pcidb_subvd_t
*
217 parse_subdev(char *buf
, pcidb_device_t
*d
)
222 s
= malloc(sizeof (pcidb_subvd_t
));
229 s
->ps_vid
= strtol(buf
, NULL
, 16);
232 s
->ps_did
= strtol(buf
, NULL
, 16);
236 if (buf
[len
-1] == '\n')
239 (void) strlcpy(s
->ps_name
, buf
, PCI_NAME_MAX
);
245 readline(FILE *f
, char *buf
, size_t len
)
248 if (fgets(buf
, len
, f
) == NULL
)
254 if (buf
[0] != '#' && buf
[0] != '\n')
260 parse_db(FILE *f
, pcidb_hdl_t
*hdl
)
263 pcidb_vendor_t
*v
= NULL
;
264 pcidb_device_t
*d
= NULL
;
265 pcidb_parse_t state
= PDB_VENDOR
;
269 if (readline(f
, buf
, sizeof (buf
)) != 0) {
279 v
= parse_vendor(buf
, hdl
);
285 if (buf
[0] != '\t') {
290 if (buf
[1] == '\t') {
296 d
= parse_device(buf
, v
);
301 if (buf
[0] != '\t') {
306 if (buf
[0] == '\t' && buf
[1] != '\t') {
311 assert(buf
[0] == '\t' && buf
[1] == '\t');
313 (void) parse_subdev(buf
, d
);
319 pcidb_open(int version
)
324 if (version
!= PCIDB_VERSION
) {
329 h
= malloc(sizeof (pcidb_hdl_t
));
336 f
= fopen(pci_db
, "rF");
342 if (parse_db(f
, h
) < 0) {
352 pcidb_close(pcidb_hdl_t
*h
)
354 pcidb_vendor_t
*v
, *tv
;
356 pcidb_device_t
*d
, *td
;
357 pcidb_subvd_t
*s
, *ts
;
385 pcidb_lookup_vendor(pcidb_hdl_t
*hdl
, uint16_t id
)
389 for (v
= hdl
->ph_vstart
; v
!= NULL
; v
= v
->pv_next
) {
398 pcidb_vendor_name(pcidb_vendor_t
*v
)
404 pcidb_vendor_id(pcidb_vendor_t
*v
)
410 pcidb_vendor_iter(pcidb_hdl_t
*h
)
412 return (h
->ph_vstart
);
416 pcidb_vendor_iter_next(pcidb_vendor_t
*v
)
423 pcidb_lookup_device_by_vendor(pcidb_vendor_t
*v
, uint16_t id
)
428 for (d
= v
->pv_dstart
; d
!= NULL
; d
= d
->pd_next
)
436 pcidb_lookup_device(pcidb_hdl_t
*h
, uint16_t vid
, uint16_t did
)
440 v
= pcidb_lookup_vendor(h
, vid
);
444 return (pcidb_lookup_device_by_vendor(v
, did
));
448 pcidb_device_iter(pcidb_vendor_t
*v
)
450 return (v
->pv_dstart
);
454 pcidb_device_iter_next(pcidb_device_t
*d
)
460 pcidb_device_name(pcidb_device_t
*d
)
466 pcidb_device_id(pcidb_device_t
*d
)
472 pcidb_device_vendor(pcidb_device_t
*d
)
478 pcidb_lookup_subvd_by_device(pcidb_device_t
*d
, uint16_t svid
, uint16_t sdid
)
484 for (s
= d
->pd_sstart
; s
!= NULL
; s
= s
->ps_next
)
485 if (s
->ps_vid
== svid
&& s
->ps_did
== sdid
)
492 pcidb_lookup_subvd_by_vendor(pcidb_vendor_t
*v
, uint16_t devid
, uint16_t svid
,
498 d
= pcidb_lookup_device_by_vendor(v
, devid
);
502 return (pcidb_lookup_subvd_by_device(d
, svid
, sdid
));
506 pcidb_lookup_subvd(pcidb_hdl_t
*h
, uint16_t vid
, uint16_t did
, uint16_t svid
,
512 d
= pcidb_lookup_device(h
, vid
, did
);
516 return (pcidb_lookup_subvd_by_device(d
, svid
, sdid
));
520 pcidb_subvd_iter(pcidb_device_t
*d
)
522 return (d
->pd_sstart
);
526 pcidb_subvd_iter_next(pcidb_subvd_t
*s
)
532 pcidb_subvd_name(pcidb_subvd_t
*s
)
538 pcidb_subvd_svid(pcidb_subvd_t
*s
)
544 pcidb_subvd_sdid(pcidb_subvd_t
*s
)
550 pcidb_subvd_device(pcidb_subvd_t
*s
)
556 pcidb_subvd_vendor(pcidb_subvd_t
*s
)