+static inline void
+pci_log_device(struct pci_device* pcidev)
+{
+ pciaddr_t loc = pcidev->loc;
+ struct device_def* binddef = pcidev->binding.def;
+
+ kprintf("pci.%03d:%02d:%02d, class=%p, vendor:dev=%04x:%04x",
+ PCILOC_BUS(loc),
+ PCILOC_DEV(loc),
+ PCILOC_FN(loc),
+ pcidev->class_info,
+ PCI_DEV_VENDOR(pcidev->device_info),
+ PCI_DEV_DEVID(pcidev->device_info));
+}
+
+static struct pci_device*
+pci_create_device(pciaddr_t loc, ptr_t pci_base, int devinfo)
+{
+ pci_reg_t class = pci_read_cspace(pci_base, 0x8);
+
+ u32_t devid = PCI_DEV_DEVID(devinfo);
+ u32_t vendor = PCI_DEV_VENDOR(devinfo);
+ pci_reg_t intr = pci_read_cspace(pci_base, 0x3c);
+
+ struct pci_device* device = vzalloc(sizeof(struct pci_device));
+ device->class_info = class;
+ device->device_info = devinfo;
+ device->cspace_base = pci_base;
+ device->intr_info = intr;
+
+ device_create(&device->dev, dev_meta(pcidev_cat), DEV_IFSYS, NULL);
+
+ pci_probe_msi_info(device);
+ pci_probe_bar_info(device);
+
+ llist_append(&pci_devices, &device->dev_chain);
+ register_device(&device->dev, &pci_def.class, "%x", loc);
+ pci_def.class.variant++;
+
+ return device;
+}
+
+int
+pci_bind_definition(struct pci_device_def* pcidev_def, int* more)
+{
+ u32_t class = pcidev_def->dev_class;
+ u32_t devid_mask = pcidev_def->ident_mask;
+ u32_t devid = pcidev_def->dev_ident & devid_mask;
+
+ if (!pcidev_def->devdef.bind) {
+ ERROR("pcidev %xh:%xh.%d is unbindable",
+ pcidev_def->devdef.class.fn_grp,
+ pcidev_def->devdef.class.device,
+ pcidev_def->devdef.class.variant);
+ return EINVAL;
+ }
+
+ *more = 0;
+
+ int bind_attempted = 0;
+ int errno = 0;
+
+ struct device_def* devdef;
+ struct pci_device *pos, *n;
+ llist_for_each(pos, n, &pci_devices, dev_chain)
+ {
+ if (binded_pcidev(pos)) {
+ continue;
+ }
+
+ if (class != PCI_DEV_CLASS(pos->class_info)) {
+ continue;
+ }
+
+ int matched = (pos->device_info & devid_mask) == devid;
+
+ if (!matched) {
+ continue;
+ }
+
+ if (bind_attempted) {
+ *more = 1;
+ break;
+ }
+
+ bind_attempted = 1;
+ devdef = &pcidev_def->devdef;
+ errno = devdef->bind(devdef, &pos->dev);
+
+ if (errno) {
+ ERROR("pci_loc:%x, bind (%xh:%xh.%d) failed, e=%d",
+ pos->loc,
+ devdef->class.fn_grp,
+ devdef->class.device,
+ devdef->class.variant,
+ errno);
+ continue;
+ }
+
+ pos->binding.def = &pcidev_def->devdef;
+ }
+
+ return errno;
+}
+
+int
+pci_bind_definition_all(struct pci_device_def* pcidef)
+{
+ int more = 0, e = 0;
+ do {
+ if (!(e = pci_bind_definition(pcidef, &more))) {
+ break;
+ }
+ } while (more);
+
+ return e;
+}
+