Skip to content

Commit 41be611

Browse files
committed
pinctrl: Use /dev/gpiomem* if available
With the correct udev rule to set the permissions, /dev/gpiomem* can make the GPIO registers available to userspace without the need for root privilege. Signed-off-by: Phil Elwell <[email protected]>
1 parent c18e12e commit 41be611

File tree

1 file changed

+38
-16
lines changed

1 file changed

+38
-16
lines changed

pinctrl/gpiolib.c

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ typedef struct GPIO_CHIP_INSTANCE_
2121
const GPIO_CHIP_T *chip;
2222
const char *name;
2323
const char *dtnode;
24+
int mem_fd;
2425
void *priv;
2526
uint64_t phys_addr;
2627
unsigned num_gpios;
@@ -409,6 +410,7 @@ int gpiolib_init(void)
409410
const GPIO_CHIP_T *chip;
410411
GPIO_CHIP_INSTANCE_T *inst;
411412
char pathbuf[FILENAME_MAX];
413+
char gpiomem_idx[4];
412414
const char *dtpath = "/proc/device-tree";
413415
const char *p;
414416
char *alias = NULL, *names, *end, *compatible;
@@ -442,10 +444,12 @@ int gpiolib_init(void)
442444
for (i = 0; ; i++)
443445
{
444446
sprintf(pathbuf, "gpio%d", i);
447+
sprintf(gpiomem_idx, "%d", i);
445448
alias = dt_read_prop("/aliases", pathbuf, NULL);
446449
if (!alias && i == 0)
447450
{
448451
alias = dt_read_prop("/aliases", "gpio", NULL);
452+
gpiomem_idx[0] = 0;
449453
}
450454
if (!alias)
451455
break;
@@ -481,6 +485,8 @@ int gpiolib_init(void)
481485
return -1;
482486
}
483487

488+
sprintf(pathbuf, "/dev/gpiomem%s", gpiomem_idx);
489+
inst->mem_fd = open(pathbuf, O_RDWR|O_SYNC);
484490
}
485491

486492
gpio_base = 0;
@@ -636,12 +642,10 @@ int gpiolib_init_by_name(const char *name)
636642

637643
int gpiolib_mmap(void)
638644
{
639-
int mem_fd;
645+
int pagesize = getpagesize();
646+
int mem_fd = -1;
640647
unsigned i;
641648

642-
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
643-
return errno;
644-
645649
for (i = 0; i < num_gpio_chips; i++)
646650
{
647651
GPIO_CHIP_INSTANCE_T *inst;
@@ -653,21 +657,39 @@ int gpiolib_mmap(void)
653657
inst = &gpio_chips[i];
654658
chip = inst->chip;
655659

656-
align = inst->phys_addr & 0xffff;
657-
gpio_map = mmap(
658-
NULL, /* Any address in our space will do */
659-
chip->size + align, /* Map length */
660-
PROT_READ | PROT_WRITE, /* Enable reading & writing */
661-
MAP_SHARED, /* Shared with other processes */
662-
mem_fd, /* File to map */
663-
inst->phys_addr - align /* Offset to GPIO peripheral */
664-
);
660+
align = inst->phys_addr & (pagesize - 1);
665661

666-
if (gpio_map == MAP_FAILED)
662+
if (inst->mem_fd >= 0)
667663
{
668-
close(mem_fd);
669-
return errno;
664+
gpio_map = mmap(
665+
NULL, /* Any address in our space will do */
666+
chip->size + align, /* Map length */
667+
PROT_READ | PROT_WRITE, /* Enable reading & writing */
668+
MAP_SHARED, /* Shared with other processes */
669+
inst->mem_fd, /* File to map */
670+
0 /* Offset to GPIO peripheral */
671+
);
670672
}
673+
else
674+
{
675+
if (mem_fd < 0)
676+
{
677+
mem_fd = open("/dev/mem", O_RDWR|O_SYNC);
678+
if (mem_fd < 0)
679+
return errno;
680+
}
681+
gpio_map = mmap(
682+
NULL, /* Any address in our space will do */
683+
chip->size + align, /* Map length */
684+
PROT_READ | PROT_WRITE, /* Enable reading & writing */
685+
MAP_SHARED, /* Shared with other processes */
686+
mem_fd, /* File to map */
687+
inst->phys_addr - align /* Offset to GPIO peripheral */
688+
);
689+
}
690+
691+
if (gpio_map == MAP_FAILED)
692+
return errno;
671693

672694
new_priv = chip->interface->gpio_probe_instance(inst->priv,
673695
(void *)((char *)gpio_map + align));

0 commit comments

Comments
 (0)