static int proc_setup(struct pci_dev *d, int rw) { struct pci_access *a = d->access; if (a->cached_dev != d || a->fd_rw < rw) { char buf[1024]; int e; if (a->fd >= 0) close(a->fd); e = snprintf(buf, sizeof(buf), "%s/%02x/%02x.%d", pci_get_param(a, "proc.path"), d->bus, d->dev, d->func); if (e < 0 || e >= (int) sizeof(buf)) a->error("File name too long"); a->fd_rw = a->writeable || rw; a->fd = open(buf, a->fd_rw ? O_RDWR : O_RDONLY); if (a->fd < 0) { e = snprintf(buf, sizeof(buf), "%s/%04x:%02x/%02x.%d", pci_get_param(a, "proc.path"), d->domain, d->bus, d->dev, d->func); if (e < 0 || e >= (int) sizeof(buf)) a->error("File name too long"); a->fd = open(buf, a->fd_rw ? O_RDWR : O_RDONLY); } if (a->fd < 0) a->warning("Cannot open %s", buf); a->cached_dev = d; a->fd_pos = 0; } return a->fd; }
pci& pci::operator=(const pci &p) { *this = p; pci_init(_pacc); _pacc->numeric_ids = 0; pci_set_param(_pacc, const_cast<char*>("proc.path"), pci_get_param(p._pacc, const_cast<char*>("proc.path"))); return *this; }
static void proc_scan(struct pci_access *a) { FILE *f; char buf[512]; if (snprintf(buf, sizeof(buf), "%s/devices", pci_get_param(a, "proc.path")) == sizeof(buf)) a->error("File name too long"); f = fopen(buf, "r"); if (!f) a->error("Cannot open %s", buf); while (fgets(buf, sizeof(buf)-1, f)) { struct pci_dev *d = pci_alloc_dev(a); unsigned int dfn, vend, cnt, known; #define F " " PCIADDR_T_FMT cnt = sscanf(buf, "%x %x %x" F F F F F F F F F F F F F F, &dfn, &vend, &d->irq, &d->base_addr[0], &d->base_addr[1], &d->base_addr[2], &d->base_addr[3], &d->base_addr[4], &d->base_addr[5], &d->rom_base_addr, &d->size[0], &d->size[1], &d->size[2], &d->size[3], &d->size[4], &d->size[5], &d->rom_size); #undef F if (cnt != 9 && cnt != 10 && cnt != 17) a->error("proc: parse error (read only %d items)", cnt); d->bus = dfn >> 8U; d->dev = PCI_SLOT(dfn & 0xff); d->func = PCI_FUNC(dfn & 0xff); d->vendor_id = vend >> 16U; d->device_id = vend & 0xffff; known = PCI_FILL_IDENT; if (!a->buscentric) { known |= PCI_FILL_IRQ | PCI_FILL_BASES; if (cnt >= 10) known |= PCI_FILL_ROM_BASE; if (cnt >= 17) known |= PCI_FILL_SIZES; } d->known_fields = known; pci_link_dev(a, d); } fclose(f); }
static void obsd_init(struct pci_access *a) { char *name = pci_get_param(a, "obsd.path"); a->fd = open(name, O_RDWR, 0); if (a->fd < 0) a->error("obsd_init: %s open failed", name); }
static void nbsd_init(struct pci_access *a) { char *name = pci_get_param(a, "nbsd.path"); int mode = a->writeable ? O_RDWR : O_RDONLY; a->fd = open(name, mode, 0); if (a->fd < 0) a->error("nbsd_init: %s open failed", name); }
static char *get_cache_name(struct pci_access *a) { char *name, *buf; name = pci_get_param(a, "net.cache_name"); if (!name || !name[0]) return NULL; if (strncmp(name, "~/", 2)) return name; uid_t uid = getuid(); struct passwd *pw = getpwuid(uid); if (!pw) return name; buf = pci_malloc(a, strlen(pw->pw_dir) + strlen(name+1) + 1); sprintf(buf, "%s%s", pw->pw_dir, name+1); pci_set_param_internal(a, "net.cache_name", buf, 1); pci_mfree(buf); return pci_get_param(a, "net.cache_name"); }
static int proc_detect(struct pci_access *a) { char *name = pci_get_param(a, "proc.path"); if (access(name, R_OK)) { a->warning("Cannot open %s", name); return 0; } a->debug("...using %s", name); return 1; }
static int nbsd_detect(struct pci_access *a) { char *name = pci_get_param(a, "nbsd.path"); if (access(name, R_OK)) { a->warning("Cannot open %s", name); return 0; } if (!access(name, W_OK)) a->writeable = O_RDWR; a->debug("...using %s", name); return 1; }
static inline char * sysfs_name(struct pci_access *a) { return pci_get_param(a, "sysfs.path"); }
char *pci_id_net_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4) { static int resolver_inited; char name[256], dnsname[256], txt[256], *domain; byte answer[4096]; const byte *data; int res, j, dlen; struct dns_state ds; domain = pci_get_param(a, "net.domain"); if (!domain || !domain[0]) return NULL; switch (cat) { case ID_VENDOR: sprintf(name, "%04x", id1); break; case ID_DEVICE: sprintf(name, "%04x.%04x", id2, id1); break; case ID_SUBSYSTEM: sprintf(name, "%04x.%04x.%04x.%04x", id4, id3, id2, id1); break; case ID_GEN_SUBSYSTEM: sprintf(name, "%04x.%04x.s", id2, id1); break; case ID_CLASS: sprintf(name, "%02x.c", id1); break; case ID_SUBCLASS: sprintf(name, "%02x.%02x.c", id2, id1); break; case ID_PROGIF: sprintf(name, "%02x.%02x.%02x.c", id3, id2, id1); break; default: return NULL; } sprintf(dnsname, "%s.%s", name, domain); a->debug("Resolving %s\n", dnsname); if (!resolver_inited) { resolver_inited = 1; res_init(); } res = res_query(dnsname, ns_c_in, ns_t_txt, answer, sizeof(answer)); if (res < 0) { a->debug("\tfailed, h_errno=%d\n", h_errno); return NULL; } if (dns_parse_packet(&ds, answer, res) < 0) { a->debug("\tMalformed DNS packet received\n"); return NULL; } dns_init_section(&ds, DNS_SEC_ANSWER); while (dns_parse_rr(&ds) > 0) { if (ds.rr_class != ns_c_in || ds.rr_type != ns_t_txt) { a->debug("\tUnexpected RR in answer: class %d, type %d\n", ds.rr_class, ds.rr_type); continue; } data = ds.rr_data; dlen = ds.rr_len; j = 0; while (j < dlen && j+1+data[j] <= dlen) { memcpy(txt, &data[j+1], data[j]); txt[data[j]] = 0; j += 1+data[j]; a->debug("\t\"%s\"\n", txt); if (txt[0] == 'i' && txt[1] == '=') return strdup(txt+2); } } return NULL; }
static void dump_init(struct pci_access *a) { char *name = pci_get_param(a, "dump.name"); FILE *f; char buf[256]; struct pci_dev *dev = NULL; int len, mn, bn, dn, fn, i, j; if (!name) a->error("dump: File name not given."); if (!(f = fopen(name, "r"))) a->error("dump: Cannot open %s: %s", name, strerror(errno)); while (fgets(buf, sizeof(buf)-1, f)) { char *z = strchr(buf, '\n'); if (!z) { fclose(f); a->error("dump: line too long or unterminated"); } *z-- = 0; if (z >= buf && *z == '\r') *z-- = 0; len = z - buf + 1; mn = 0; if ((dump_validate(buf, "##:##.# ") && sscanf(buf, "%x:%x.%d", &bn, &dn, &fn) == 3) || (dump_validate(buf, "####:##:##.# ") && sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4)) { dev = pci_get_dev(a, mn, bn, dn, fn); dump_alloc_data(dev, 256); pci_link_dev(a, dev); } else if (!len) dev = NULL; else if (dev && (dump_validate(buf, "##: ") || dump_validate(buf, "###: ")) && sscanf(buf, "%x: ", &i) == 1) { struct dump_data *dd = dev->aux; z = strchr(buf, ' ') + 1; while (isxdigit(z[0]) && isxdigit(z[1]) && (!z[2] || z[2] == ' ') && sscanf(z, "%x", &j) == 1 && j < 256) { if (i >= 4096) { fclose(f); a->error("dump: At most 4096 bytes of config space are supported"); } if (i >= dd->allocated) /* Need to re-allocate the buffer */ { dump_alloc_data(dev, 4096); memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256); pci_mfree(dd); dd = dev->aux; } dd->data[i++] = j; if (i > dd->len) dd->len = i; z += 2; if (*z) z++; } if (*z) { fclose(f); a->error("dump: Malformed line"); } } } fclose(f); }
static int dump_detect(struct pci_access *a) { char *name = pci_get_param(a, "dump.name"); return name && name[0]; }
pci::pci(const pci &p) : _pacc(nullptr) { *this = p; pci_init(_pacc); _pacc->numeric_ids = 0; pci_set_param(_pacc, const_cast<char*>("proc.path"), pci_get_param(p._pacc, const_cast<char*>("proc.path"))); }