/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
/*
* This library exists to understand and parse the pci.ids database that is
* maintained at http://pci-ids.ucw.cz/ and in the gate at cmd/hwdata. This
* database provides a way to map the PCI device, vendor, and subsystem ids to
* a human understandable name.
*
* This library exports this data in a similar way to a tree. The handle that
* is returned from pcidb_open is the root of the tree. The next level are the
* vendors. Each vendor has a unique set of devices and each device has a unique
* set of subvendor and subdevice pairs.
*
* Parsing information:
*
* The database is formatted in the following basic format:
* vendor_id<two spaces>vendor_name
* <tab>device_id<two spaces>device_name
* <tab><tab>subvendor<space>subdevice<two spaces>subsystem_name
*
* For any given vendor, there can be multiple devices. And for any given device
* there will be multiple subsystems. In addition, there can be comments that
* start a line which use the '#' character.
*
* At the end of the file, there are a series of PCI classes. Those will start
* with a single C<space>. Once we hit those, we stop all parsing. We currently
* don't care about consuming or presenting those.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "pcidb.h"
/* Forward declarations */
struct pcidb_vendor;
struct pcidb_device;
struct pcidb_subvd;
struct pcidb_subvd {
};
struct pcidb_device {
};
struct pcidb_vendor {
};
struct pcidb_hdl {
};
typedef enum pcidb_parse {
static void
{
} else {
}
}
static pcidb_vendor_t *
{
pcidb_vendor_t *v;
v = malloc(sizeof (pcidb_vendor_t));
if (v == NULL)
return (NULL);
pcihdl_add_vendor(hdl, v);
buf += 6;
return (v);
}
static void
{
d->pd_vend = v;
v->pv_dstart = d;
v->pv_dend = d;
} else {
v->pv_dend = d;
}
}
static pcidb_device_t *
{
pcidb_device_t *d;
d = malloc(sizeof (pcidb_device_t));
if (d == NULL)
return (d);
insert_device(v, d);
buf++;
buf += 6;
return (d);
}
static void
{
s->ps_dev = d;
d->pd_sstart = s;
d->pd_send = s;
} else {
d->pd_send = s;
}
}
static pcidb_subvd_t *
{
pcidb_subvd_t *s;
s = malloc(sizeof (pcidb_subvd_t));
if (s == NULL)
return (NULL);
insert_subdev(d, s);
buf += 2;
buf += 5;
buf += 6;
return (s);
}
static int
{
for (;;) {
return (-1);
if (buf[0] == 'C')
return (-1);
return (0);
}
}
static int
{
pcidb_vendor_t *v = NULL;
pcidb_device_t *d = NULL;
for (;;) {
errno = 0;
if (errno != 0)
return (-1);
else
return (0);
}
switch (state) {
case PDB_VENDOR:
if (v == NULL)
return (NULL);
state = PDB_DEVICE;
continue;
case PDB_DEVICE:
if (buf[0] != '\t') {
state = PDB_VENDOR;
goto newstate;
}
state = PDB_SUBDEV;
goto newstate;
}
d = parse_device(buf, v);
if (d == NULL)
return (NULL);
continue;
case PDB_SUBDEV:
if (buf[0] != '\t') {
state = PDB_VENDOR;
goto newstate;
}
state = PDB_DEVICE;
goto newstate;
}
(void) parse_subdev(buf, d);
}
}
}
{
pcidb_hdl_t *h;
FILE *f;
if (version != PCIDB_VERSION) {
return (NULL);
}
h = malloc(sizeof (pcidb_hdl_t));
if (h == NULL)
return (NULL);
if (f == NULL) {
free(h);
return (NULL);
}
if (parse_db(f, h) < 0) {
pcidb_close(h);
free(h);
return (NULL);
}
return (h);
}
void
{
if (h == NULL)
return;
v = h->ph_vstart;
while (v != NULL) {
d = v->pv_dstart;
while (d != NULL) {
s = d->pd_sstart;
while (s != NULL) {
ts = s;
s = s->ps_next;
}
td = d;
d = d->pd_next;
}
tv = v;
v = v->pv_next;
}
free(h);
}
{
pcidb_vendor_t *v;
return (v);
}
return (NULL);
}
const char *
{
return (v->pv_name);
}
{
return (v->pv_id);
}
{
return (h->ph_vstart);
}
{
return (v->pv_next);
}
{
pcidb_device_t *d;
return (d);
return (NULL);
}
{
pcidb_vendor_t *v;
v = pcidb_lookup_vendor(h, vid);
if (v == NULL)
return (NULL);
return (pcidb_lookup_device_by_vendor(v, did));
}
{
return (v->pv_dstart);
}
{
return (d->pd_next);
}
const char *
{
return (d->pd_name);
}
{
return (d->pd_id);
}
{
return (d->pd_vend);
}
{
pcidb_subvd_t *s;
return (s);
return (NULL);
}
{
pcidb_device_t *d;
d = pcidb_lookup_device_by_vendor(v, devid);
if (d == NULL)
return (NULL);
}
{
pcidb_device_t *d;
if (d == NULL)
return (NULL);
}
{
return (d->pd_sstart);
}
{
return (s->ps_next);
}
const char *
{
return (s->ps_name);
}
{
return (s->ps_vid);
}
{
return (s->ps_did);
}
{
return (s->ps_dev);
}
{
return (s->ps_vend);
}