int fpga_pci_get_dma_device_num()

in sdk/userspace/fpga_libs/fpga_dma/fpga_dma_utils.c [178:287]


int fpga_pci_get_dma_device_num(enum fpga_dma_driver which_driver,
    int slot_id, int *device_num)
{
    int rc;
    char dbdf[16];
    char path[64];
    int _device_num;
    struct dirent *entry;
    char real_path[MAX_FD_LEN];
    char *possible_dbdf = NULL;
    struct fpga_pci_resource_map resource;
    char sysfs_path_instance[MAX_FD_LEN + sizeof(entry->d_name) + sizeof(path)];

    const struct dma_opts_s *dma_opts = fpga_dma_get_dma_opts(which_driver);
    fail_on_with_code(!dma_opts, err, rc, -EINVAL, "invalid DMA driver");
    rc = snprintf(path, sizeof(path), "/sys/class/%s", dma_opts->drv_name);
    fail_on_with_code(rc < 1, err, rc, FPGA_ERR_SOFTWARE_PROBLEM,
        "snprintf failed");

    /* This call must be before the lock, because the call holds the lock. */
    rc = fpga_pci_get_resource_map(slot_id, FPGA_APP_PF, &resource);
    fail_on(rc, err, "Could not get resource map");
    rc = snprintf(dbdf,
                  sizeof(dbdf),
                  PCI_DEV_FMT,
                  resource.domain,
                  resource.bus,
                  resource.dev,
                  resource.func);
    fail_on_with_code(rc < 1, err, rc, FPGA_ERR_SOFTWARE_PROBLEM,
        "Could not record DBDF");

    DIR *dirp = opendir(path);
    fail_on_with_code(!dirp, err, rc, FPGA_ERR_SOFTWARE_PROBLEM,
        "opendir failed for path=%s", path);

#if defined(FPGA_PCI_USE_READDIR_R)
    struct dirent entry_stack, *result;
    entry = &entry_stack;
    memset(entry, 0, sizeof(struct dirent));
#else
    /**
     * Protect calls to readdir with a mutex because multiple threads may call
     * this function, which always reads from the same directory. The man page
     * for readdir says the POSIX spec does not require threadsafety.
     */
    fpga_acquire_readdir_lock();
#endif

    while (true) {
        /* reset so that the loop termination detection below works */
        _device_num = -1;

#if defined(FPGA_PCI_USE_READDIR_R)
        memset(entry, 0, sizeof(struct dirent));
        readdir_r(dirp, entry, &result);
        if (result == NULL) {
            /** No more directories */
            break;
        }
#else
        entry = readdir(dirp);
        if (entry == NULL) {
            /** No more directories */
            break;
        }
#endif

        rc = (*dma_opts->get_dev_number_f)(entry->d_name, &_device_num);
        if (rc != 0) {
            continue;
        }

        rc = snprintf(sysfs_path_instance, sizeof(sysfs_path_instance),
            "%s/%s/device", path, entry->d_name);
        fail_on_with_code(rc < 2, err_unlock, rc, FPGA_ERR_SOFTWARE_PROBLEM,
            "snprintf failed to build sysfs path");
        possible_dbdf = realpath(sysfs_path_instance, real_path);
        if (possible_dbdf == NULL) {
            continue;
        }
        possible_dbdf = basename(real_path);
        if (strncmp(possible_dbdf, dbdf, 12) == 0) {
            break; /* found device */
        }
        /* continue... */
    }
#if !defined(FPGA_PCI_USE_READDIR_R)
    fpga_release_readdir_lock();
#endif
    fail_on_with_code(_device_num == -1, err, rc, FPGA_ERR_PCI_MISSING,
        "Unable to find device num");

    closedir(dirp);
    *device_num = _device_num;
    errno = 0;
    return 0;

err_unlock:
#if !defined(FPGA_PCI_USE_READDIR_R)
    fpga_release_readdir_lock();
#endif

err:
    if (dirp) {
        closedir(dirp);
    }
    errno = 0;
    return rc;
}