/*
* k8temp functions for scanning PCI devices and reading/writing
* to registers on them, via FreeBSD-style /dev/pci
*
* Supported on FreeBSD and DragonFlyBSD.
*
* OpenBSD should work with USER_PCI and -DWITHOUT_PCIOCGETCONF
*
* NetBSD needs libpci, using pcibus_conf_read()/write()
*
* Linux can probably work with /proc/pci or something?
*
* No idea about Solaris.
*/
#include <sysexits.h>
#include "k8temp_pci.h"
static int fd;
void
k8_pci_init()
{
if ((fd = open(_PATH_DEVPCI, O_RDWR, 0)) < 0)
err(EX_OSFILE, "open(\"%s\")", _PATH_DEVPCI);
}
void
k8_pci_close()
{
if (fd) close(fd);
}
int
k8_pci_vendor_device_list(uint32_t vendor_id, uint32_t device_id, k8_pcidev devs[], int maxdev)
{
int matches = -1;
#ifndef WITHOUT_PCIOCGETCONF
struct pci_conf_io pc;
struct pci_match_conf pat;
struct pci_conf conf[255], *p;
bzero(&pc, sizeof(struct pci_conf_io));
bzero(&pat, sizeof(struct pci_match_conf));
pat.pc_vendor = vendor_id;
pat.pc_device = device_id;
pat.flags = PCI_GETCONF_MATCH_VENDOR | PCI_GETCONF_MATCH_DEVICE;
pc.patterns = &pat;
pc.num_patterns = 1;
pc.pat_buf_len = sizeof(pat);
pc.match_buf_len = sizeof(conf);
pc.matches = conf;
if (ioctl(fd, PCIOCGETCONF, &pc) == -1 || pc.status == PCI_GETCONF_ERROR)
{
warn("ioctl(PCIOCGETCONF) failed");
return(-1);
}
for (p = conf; p < &conf[pc.num_matches]; p++)
{
if (matches < maxdev)
memcpy(&devs[++matches], &p->pc_sel, sizeof(k8_pcidev));
}
#else
/* should work with OpenBSD's USER_PCI */
uint8_t dev,func;
uint32_t pcireg;
k8_pcidev sel;
bzero(&sel, sizeof(k8_pcidev));
sel.pc_bus = 0;
for (dev=0; dev < 32; dev++)
{
sel.pc_dev = dev;
for (func=0; func < 8; func++)
{
sel.pc_func = func;
if (k8_pci_read_word(sel, 0, &pcireg))
{
if ((pcireg & 0xffff) == vendor_id &&
((pcireg >> 16) & 0xffff) == device_id &&
matches < maxdev)
{
memcpy(&devs[++matches], &sel, sizeof(k8_pcidev));
}
}
}
}
#endif
return(matches);
}
int
k8_pci_read(k8_pcidev dev, int offset, uint32_t *data, int width)
{
struct pci_io ctrl;
bzero(&ctrl, sizeof(ctrl));
ctrl.pi_sel = dev;
ctrl.pi_reg = offset;
ctrl.pi_width = width;
if (ioctl(fd, PCIOCREAD, &ctrl) == -1)
{
warn("Register read %x, %d bytes failed", offset, width);
return(0);
}
*data = ctrl.pi_data;
return(width);
}
int
k8_pci_read_byte(k8_pcidev dev, int offset, uint32_t *data)
{
return(k8_pci_read(dev, offset, data, 1));
}
int
k8_pci_read_word(k8_pcidev dev, int offset, uint32_t *data)
{
return(k8_pci_read(dev, offset, data, 4));
}
int
k8_pci_write(k8_pcidev dev, int offset, uint32_t data, int width)
{
struct pci_io ctrl;
bzero(&ctrl, sizeof(ctrl));
ctrl.pi_sel = dev;
ctrl.pi_reg = offset;
ctrl.pi_width = width;
ctrl.pi_data = data;
if (ioctl(fd, PCIOCWRITE, &ctrl) == -1)
{
warn("Register write %x, %d bytes failed", offset, width);
return(0);
}
return(width);
}
int
k8_pci_write_byte(k8_pcidev dev, int offset, uint32_t data)
{
return(k8_pci_write(dev, offset, data, 1));
}
int
k8_pci_write_word(k8_pcidev dev, int offset, uint32_t data)
{
return(k8_pci_write(dev, offset, data, 4));
}
syntax highlighted by Code2HTML, v. 0.9.1