Raspberry Pi 2: Denials using RPi.GPIO

After learning that I needed to use the edge image for the rpi2 in order to use GPIO, I’m getting some denials using RPi.GPIO just trying to write to GPIO pins, like this:

#!/usr/bin/env python3

import RPi.GPIO as GPIO
# Set the GPIO modes
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(7, GPIO.OUT)
GPIO.output(7, 0)
GPIO.cleanup()

snappy-debug gives me this:

= AppArmor =
Time: Nov 29 02:24:01
Log: apparmor="DENIED" operation="open" profile="snap.my-snap-name.wheels" name="/dev/gpiomem" pid=3263 comm="python3" requested_mask="wr" denied_mask="wr" fsuid=0 ouid=0
File: /dev/gpiomem (write)

= AppArmor =
Time: Nov 29 02:24:01
Log: apparmor="DENIED" operation="open" profile="snap.my-snap-name.wheels" name="/sys/firmware/devicetree/base/soc/ranges" pid=3263 comm="python3" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
File: /sys/firmware/devicetree/base/soc/ranges (read)
Suggestion:
* adjust program to not access '/sys/firmware/devicetree/base/soc/ranges'

= AppArmor =
Time: Nov 29 02:24:01
Log: apparmor="DENIED" operation="open" profile="snap.my-snap-name.wheels" name="/dev/mem" pid=3263 comm="python3" requested_mask="wr" denied_mask="wr" fsuid=0 ouid=0
File: /dev/mem (write)
Suggestion:
* add 'physical-memory-control' to 'plugs'

Note that every GPIO slot is connected. Ignoring the physical memory control one, anyone have any ideas?

The particular GPIO library seems to use /dev/mem for that. I think we are out of luck. I the /dev/gpiomem device is interesting and quickly reading about it seems to imply it’s the thing we’d like to special-case for GPIOs but it is not as fine-grained as our current GPIO access.

Given that there are now ~four ways to use GPIO that I know about, each with their own APIs and permissions, maybe it would make sense to reflect this in the interface layer:

AFAIK there are:

  • sysfs based gpioexport things (standard, deprecated)
  • new /dev/gpiochipN interface (haven’t tried that, replaces the sysfs API)
  • /dev/mem and wild-west of “works on RPi” python/node packages
  • /dev/gpiomem which I know little about

It seems /dev/mem is used as a fallback if /dev/gpiomem is unavailable. @jdstrand do you know anything about /dev/gpiomem ? Is that something we should support?

Doing a bit of research, found this. Sounds like sysfs is too slow, which is why such libs use /dev/mem or /dev/gpiomem. Would be great if we can figure out how to support this, or we exclude applications that need to operate at, say, MHz speeds.

Also found this, which leads me to believe that while /dev/gpiomem is powerful, it only grants access to GPIO as opposed to /dev/mem which is everything.

We don’t have a snapd interface that grants access to all GPIOs (our current interface is per-pin). We’d have to add something like that. While we do that we should look at gpiochip API to see if we can have some sanity across the many interfaces.

[…] our current interface is per-pin

Right, which maps well to the slow sysfs interface, but not the faster memory-mapped one. Although I don’t know anything about /dev/gpiochip. Note that I don’t see any /dev/gpiochipX devices on the rpi2. Are we missing support for it in our kernel/gadget?

The gpiochip is a new kernel feature, probably not enabled in our kernels yet. I found this interesting: https://github.com/adafruit/adafruit-beaglebone-io-python/issues/157

Ah, yeah that seems a ways off yet, particularly considering the kernel/gadget situation for the rpi in Ubuntu Core right now. In the meantime, do you think having an interface for /dev/gpiomem seems reasonable?

Me personally yes, it’s just a matter of not making it hard for our users. I’d like to see how this fits into the gpio interface, perhaps we can have a plug that has this syntax:

plugs:
    all-gpios

This could give us access to all the GPIOs and would require a manual connection, the slot would be implicitly defined by core.

I’m not quite familiar with how the gpio interface works, is it tied to being pin-speciifc? I know the gpio slots are currently provided by the gadget. What if the core simply started providing one that covers /dev/gpiomem? Then if an app plugged gpio and was connected to core:gpio it gets /dev/gpiomem as opposed to the pin-specific ones provided by the gadget.

Yes, the gpio interface is specific to a given pin and has to be defined by the gadget. The new interface could be defined by the core as I said above.

Okay so this really is a new interface. Note that this interface also seems required for PWM without needing to modify the boot config or devicetree. Although that could possibly only be /dev/mem, I’m unclear.

After some discussion on IRC (and of course some testing), a new “gpio-memory-control” interface has been proposed here:

1 Like