10f66f451Sopenharmony_ci/*
20f66f451Sopenharmony_ci * lspci - written by Isaac Dunham
30f66f451Sopenharmony_ci
40f66f451Sopenharmony_ciUSE_LSPCI(NEWTOY(lspci, "emkn"USE_LSPCI_TEXT("@i:"), TOYFLAG_USR|TOYFLAG_BIN))
50f66f451Sopenharmony_ci
60f66f451Sopenharmony_ciconfig LSPCI
70f66f451Sopenharmony_ci  bool "lspci"
80f66f451Sopenharmony_ci  default y
90f66f451Sopenharmony_ci  help
100f66f451Sopenharmony_ci    usage: lspci [-ekm]
110f66f451Sopenharmony_ci
120f66f451Sopenharmony_ci    List PCI devices.
130f66f451Sopenharmony_ci
140f66f451Sopenharmony_ci    -e	Print all 6 digits in class
150f66f451Sopenharmony_ci    -k	Print kernel driver
160f66f451Sopenharmony_ci    -m	Machine readable format
170f66f451Sopenharmony_ci
180f66f451Sopenharmony_ciconfig LSPCI_TEXT
190f66f451Sopenharmony_ci  bool "lspci readable output"
200f66f451Sopenharmony_ci  depends on LSPCI
210f66f451Sopenharmony_ci  default y
220f66f451Sopenharmony_ci  help
230f66f451Sopenharmony_ci    usage: lspci [-n] [-i FILE ]
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_ci    -n	Numeric output (repeat for readable and numeric)
260f66f451Sopenharmony_ci    -i	PCI ID database (default /usr/share/misc/pci.ids)
270f66f451Sopenharmony_ci
280f66f451Sopenharmony_ci*/
290f66f451Sopenharmony_ci
300f66f451Sopenharmony_ci#define FOR_lspci
310f66f451Sopenharmony_ci#include "toys.h"
320f66f451Sopenharmony_ci
330f66f451Sopenharmony_ciGLOBALS(
340f66f451Sopenharmony_ci  char *i;
350f66f451Sopenharmony_ci  long n;
360f66f451Sopenharmony_ci
370f66f451Sopenharmony_ci  FILE *db;
380f66f451Sopenharmony_ci)
390f66f451Sopenharmony_ci
400f66f451Sopenharmony_cistatic int do_lspci(struct dirtree *new)
410f66f451Sopenharmony_ci{
420f66f451Sopenharmony_ci  char *p = toybuf, *vendor = toybuf+9, *device = toybuf+18,
430f66f451Sopenharmony_ci       driver[256], *vbig = 0, *dbig = 0, **fields;
440f66f451Sopenharmony_ci  int dirfd;
450f66f451Sopenharmony_ci
460f66f451Sopenharmony_ci  if (!new->parent) return DIRTREE_RECURSE;
470f66f451Sopenharmony_ci
480f66f451Sopenharmony_ci  // Parse data out of /proc
490f66f451Sopenharmony_ci
500f66f451Sopenharmony_ci  if (-1 == (dirfd = openat(dirtree_parentfd(new), new->name, O_RDONLY)))
510f66f451Sopenharmony_ci    return 0;
520f66f451Sopenharmony_ci
530f66f451Sopenharmony_ci  *driver = 0;
540f66f451Sopenharmony_ci  if (FLAG(k)) readlinkat0(dirfd, "driver", driver, sizeof(driver));
550f66f451Sopenharmony_ci
560f66f451Sopenharmony_ci  for (fields = (char*[]){"class", "vendor", "device", 0}; *fields; fields++) {
570f66f451Sopenharmony_ci    int fd, size = 6 + 2*(FLAG(e) && p == toybuf);
580f66f451Sopenharmony_ci    *p = 0;
590f66f451Sopenharmony_ci
600f66f451Sopenharmony_ci    if (-1 == (fd = openat(dirfd, *fields, O_RDONLY))) {
610f66f451Sopenharmony_ci      close(dirfd);
620f66f451Sopenharmony_ci      return 0;
630f66f451Sopenharmony_ci    }
640f66f451Sopenharmony_ci    xreadall(fd, p, size);
650f66f451Sopenharmony_ci    memmove(p, p+2, size -= 2);
660f66f451Sopenharmony_ci    p[size] = 0;
670f66f451Sopenharmony_ci    close(fd);
680f66f451Sopenharmony_ci    p += 9;
690f66f451Sopenharmony_ci  }
700f66f451Sopenharmony_ci
710f66f451Sopenharmony_ci  close(dirfd);
720f66f451Sopenharmony_ci
730f66f451Sopenharmony_ci  // Lookup/display data from pci.ids?
740f66f451Sopenharmony_ci
750f66f451Sopenharmony_ci  if (CFG_LSPCI_TEXT && TT.db) {
760f66f451Sopenharmony_ci    if (TT.n != 1) {
770f66f451Sopenharmony_ci      char *s;
780f66f451Sopenharmony_ci
790f66f451Sopenharmony_ci      fseek(TT.db, 0, SEEK_SET);
800f66f451Sopenharmony_ci      while (!vbig || !dbig) {
810f66f451Sopenharmony_ci        s = p;
820f66f451Sopenharmony_ci        if (!fgets(s, sizeof(toybuf)-(p-toybuf)-1, TT.db)) break;
830f66f451Sopenharmony_ci        while (isspace(*s)) s++;
840f66f451Sopenharmony_ci        if (*s == '#') continue;
850f66f451Sopenharmony_ci        if (vbig && s == p) break;
860f66f451Sopenharmony_ci        if (strstart(&s, vbig ? device : vendor)) {
870f66f451Sopenharmony_ci          if (vbig) dbig = s+2;
880f66f451Sopenharmony_ci          else vbig = s+2;
890f66f451Sopenharmony_ci          s += strlen(s);
900f66f451Sopenharmony_ci          s[-1] = 0; // trim ending newline
910f66f451Sopenharmony_ci          p = s + 1;
920f66f451Sopenharmony_ci        }
930f66f451Sopenharmony_ci      }
940f66f451Sopenharmony_ci    }
950f66f451Sopenharmony_ci
960f66f451Sopenharmony_ci    if (TT.n > 1) {
970f66f451Sopenharmony_ci      printf(FLAG(m) ? "%s, \"%s\" \"%s [%s]\" \"%s [%s]\""
980f66f451Sopenharmony_ci        : "%s Class %s: %s [%s] %s [%s]",
990f66f451Sopenharmony_ci        new->name+5, toybuf, vbig ? vbig : "", vendor,
1000f66f451Sopenharmony_ci        dbig ? dbig : "", device);
1010f66f451Sopenharmony_ci
1020f66f451Sopenharmony_ci      goto driver;
1030f66f451Sopenharmony_ci    }
1040f66f451Sopenharmony_ci  }
1050f66f451Sopenharmony_ci
1060f66f451Sopenharmony_ci  printf(FLAG(m) ? "%s \"%s\" \"%s\" \"%s\"" : "%s Class %s: %s:%s",
1070f66f451Sopenharmony_ci    new->name+5, toybuf, vbig ? vbig : vendor, dbig ? dbig : device);
1080f66f451Sopenharmony_ci
1090f66f451Sopenharmony_cidriver:
1100f66f451Sopenharmony_ci  if (*driver) printf(FLAG(m) ? " \"%s\"" : " %s", basename(driver));
1110f66f451Sopenharmony_ci  xputc('\n');
1120f66f451Sopenharmony_ci
1130f66f451Sopenharmony_ci  return 0;
1140f66f451Sopenharmony_ci}
1150f66f451Sopenharmony_ci
1160f66f451Sopenharmony_civoid lspci_main(void)
1170f66f451Sopenharmony_ci{
1180f66f451Sopenharmony_ci  if (CFG_LSPCI_TEXT && TT.n != 1) {
1190f66f451Sopenharmony_ci    if (!TT.i) TT.i = "/usr/share/misc/pci.ids";
1200f66f451Sopenharmony_ci    if (!(TT.db = fopen(TT.i, "r"))) perror_msg("%s", TT.i);
1210f66f451Sopenharmony_ci  }
1220f66f451Sopenharmony_ci
1230f66f451Sopenharmony_ci  dirtree_read("/sys/bus/pci/devices", do_lspci);
1240f66f451Sopenharmony_ci}
125