+#include <alloca.h>
+
+/****************************************************************/
+
+typedef struct bar_mapping_t {
+ uintptr_t virt_addr;
+ void * mmap_addr;
+ uintptr_t phys_addr;
+ uint32_t size;
+ uint32_t offset;
+} bar_mapping_t;
+
+int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
+{
+ FILE *file;
+ void *s;
+ int ssiz;
+ ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr);
+ if (ssiz < 0)
+ return -1;
+ /* add reserve to store each size addr, name, offset, size */
+ ssiz += 6 + 1;
+ s = alloca(ssiz + 6 + 1);
+
+ snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr);
+ file = fopen(s, "rb");
+ fscanf(file, "%"SCNiPTR, &barmap->phys_addr);
+ fclose(file);
+
+ snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr);
+ file = fopen(s, "rb");
+ fscanf(file, "%"SCNi32, &barmap->offset);
+ fclose(file);
+
+ snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr);
+ file = fopen(s, "rb");
+ fscanf(file, "%"SCNi32, &barmap->size);
+ fclose(file);
+
+ return 0;
+}
+
+int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
+{
+ static size_t page_mask = 0;
+ off_t mmap_offset;
+ size_t mmap_size;
+
+ if (!page_mask)
+ page_mask = sysconf(_SC_PAGESIZE) - 1;
+
+ mmap_offset = barmap->offset & ~page_mask;
+ mmap_size = barmap->offset + barmap->size + page_mask - mmap_offset;
+ mmap_size &= ~page_mask;
+
+ barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_offset);
+ if (barmap->mmap_addr == MAP_FAILED) {
+ return -1;
+ }
+
+ barmap->virt_addr = (uintptr_t)barmap->mmap_addr;
+ barmap->virt_addr += barmap->offset & page_mask;
+
+ return 0;
+}
+
+/****************************************************************/