📜 ⬆️ ⬇️

A note about the new linux kernel interface - gpio uapi

Starting with the 4.6-r1 kernel version, we have a new interface available for interacting with the gpio kernel subsystem. Now there are three official ways to work with gpio and receive interruptions from them. It makes no sense to delve into the needs for this subsystem, for a small part of it is harsh everyday life, for the other part a fun hobby, and for all together in the core a new opportunity for interaction was provided.


The note is of a popular nature, since we will not touch upon the main advantages that came with the innovation, namely the simplification of working with gpio in the context of the kernel.


New uapi gpio interface


https://github.com/torvalds/linux/blob/master/include/uapi/linux/gpio.h


First, now gpiochip is really a device and can be seen in devfs as gpiochipN , where N is the chip number assigned in the initialization order . Secondly, all setup is now done via ioctl . And thirdly, reading and writing, surprisingly, is accomplished through read / write calls, albeit with the help of a special struct gpiohandle_data structure.


gpio-mockup


Starting with the v4.9-rc1 kernel version (it will actually be used only in versions older than v4.12-rc1), a virtual gpio device has become available, with support for managing states via debugfs .


Consider the difference between sysfs and uapi in userspace.


Gpio-mockup initialization


Options:



# modprobe gpio-mockup gpio_mockup_ranges=0,8,8,16 

With this command we created two gpiochip with 8 lines each, with ranges [0-8), [8,16). We'll talk about gpio_mockup_named_lines later.


Sysfs versus uapi


With the help of the new driver, we consider the differences between the two systems from the user's point of view.


Information about gpiochip's


sysfs


  # cat /sys/class/gpio/gpiochip*/base 0 8 # cat /sys/class/gpio/gpiochip*/ngpio 8 8 # cat /sys/class/gpio/gpiochip*/label gpio-mockup-A gpio-mockup-B 

uapi


  struct gpiochip_info chip_info; ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip_info); 

  # ./lsgpio | grep GPIO\ chip GPIO chip: gpiochip1, "gpio-mockup-B", 8 GPIO lines GPIO chip: gpiochip0, "gpio-mockup-A", 8 GPIO lines 

Setting the line as an input and reading the value


sysfs


  # echo in > /sys/class/gpio/gpio0/direction # cat /sys/class/gpio/gpio0/value 

uapi


  struct gpiohandle_request req; req.lineoffsets[0] = 0; req.flags = GPIOHANDLE_REQUEST_INPUT; req.lines = 1; struct gpiohandle_data data; ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); 

Set line as output


sysfs


  # echo high > /sys/class/gpio/gpio0/direction 

uapi


  struct gpiohandle_request req; req.lineoffsets[0] = 0; req.flags = GPIOHANDLE_REQUEST_OUTPUT; req.default_values[0] = 1; req.lines = 1; ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); 

Edge handling


sysfs


  # echo both > /sys/class/gpio/gpio0/edge 

uapi


  struct gpioevent_request ereq; ereq.lineoffset = 0; ereq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &ereq); 

Polling on events


The kernel documentation for sysfs specifies the use of EPOLLPRI and EPOLLERR (or except fds for select), which in principle is typical for any sysfs_notify call, not necessarily for the gpio subsystem.


For uapi, EPOLLIN is sufficient.


  struct epoll_event event; event.data.fd = ereq.fd; event.events = EPOLLIN; epoll_ctl(epollfd, EPOLL_CTL_ADD, ereq.fd, &event); 

We are reading an event with a time stamp and type GPIOEVENT_EVENT_RISING_EDGE or GPIOEVENT_EVENT_FALLING_EDGE .


  struct gpioevent_data event; read(pin->fd, &event, sizeof(event)); 

EPOLLET for uapi works according to the epoll documentation.


labels


Small note for sysfs


The name of the contact gpioN to which everyone is so accustomed, generally speaking, is not canonical, but is used if the contact has not been given a name, for example, in Device Tree.


  // drivers/gpio/gpiolib-sysfs.c // int gpiod_export(struct gpio_desc *desc, bool direction_may_change) offset = gpio_chip_hwgpio(desc); if (chip->names && chip->names[offset]) ioname = chip->names[offset]; dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), data, gpio_groups, ioname ? ioname : "gpio%u", desc_to_gpio(desc)); 

Let's try gpio-mockup with the gpio_mockup_named_lines option:


  # modprobe gpio-mockup gpio_mockup_ranges=0,8,8,16 gpio_mockup_named_lines=1 # echo 0 > /sys/class/gpio/export # ls /sys/class/gpio/gpio-mockup-A-0 active_low device direction edge power subsystem uevent value 

As we see, the contact name has acquired the form gpio_chip_label - gpio_offset , but this is true only for the gpio-mockup driver .


  // drivers/gpio/gpio-mockup.c // static int gpio_mockup_name_lines(struct device *dev, struct gpio_mockup_chip *chip) for (i = 0; i < gc->ngpio; i++) names[i] = devm_kasprintf(dev, GFP_KERNEL, "%s-%d", gc->label, i); 

There is no way to "guess" in advance whether a name exists for a contact without using uapi , and searching for an exported "named" line is difficult if the name is not known in advance (again, if known, then we need the name and offset on the known gpiochip ).


uapi


The uapi interface allows us to see the names of the lines without initialization:


  #./lsgpio | grep gpio-mockup-A GPIO chip: gpiochip0, "gpio-mockup-A", 8 GPIO lines line 0: "gpio-mockup-A-0" unused [output] ... line 7: "gpio-mockup-A-7" unused [output] 

With the corresponding device tree file (example is taken from the kernel documentation):


  gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R", "LED G", "LED B", "Col A", "Col B", "Col C", "Col D", "Row A", "Row B", "Row C", "Row D", "NMI button", "poweroff", "reset"; 

We would see the name in the struct gpioline_info for each contact, unfortunately, few people name the contacts, even for the distributed SBC.


Uapi features not available for sysfs


Now we list the advantages inaccessible to the old interface.


I consider the main advantage to be the timestamp assigned to the event in the upper half of the interrupt handler. What is indispensable for applications that are important is the accuracy of measuring the time between events.


  le->timestamp = ktime_get_real_ns(); 

If the device driver allows, the line can optionally be configured as an open collector ( GPIOLINE_FLAG_OPEN_DRAIN ) or an open emitter ( GPIOLINE_FLAG_OPEN_SOURCE ), this innovation can be easily transferred to sysfs , but this will not be the case with Linus Werli.


Also, the new api allows you to assign custom labels to each contact during initialization in the struct gpiohandle_request field consumer_label .


And finally, it allows you to "read" and "write" immediately a group of states for contacts.


Conclusion compared


Subjectively, uapi looks more cumbersome than sysfs , but do not forget that we compared management through standard utilities GNU cat and echo and C code, if you compare C code for each of the interfaces, you get about the same in complexity and volume.


The important point is that when using sysfs, the line remains initialized until the user asks for the reverse or before rebooting. uapi frees the line immediately after closing the file descriptor.


Uapi advantages



Uapi criticism


There is no official or unofficial criticism, or I have not found it. Therefore, we will manage a couple of your own thoughts.



Criticism sysfs gpio


Let's finish with the official criticism of the sysfs interface. Linus Werli (maintainer in the core of the gpio subsystem and pinctrl) in the comments to the patches put forward the following theses:



In general, and, frankly, I believe that sysfs is quite normal for those tasks that are assigned to gpio in userspace. There is something romantic about it, when people who are not even familiar with the fundamentals of electrical engineering could light the lights with echo . With the help of the new interface, such a direct connection is not felt, since additional utilities for interaction are now required.


But GPIOs are often used together as a group. Consider a pair of GPIOs used as an I2C bus; one line handles data

I can’t say anything about the first thesis, I have never come across such a need, in the end you can immediately initialize the contacts as inputs or outputs in the device tree . I know that this functionality would be useful to those who need bit-banging in user-space , but here there is one but, on pure linux, bit-banging is possible except for very low-frequency things, and at least PREEMPT_RT patch is needed .


The second thesis is also strange I can not imagine such a saving of space that would be necessary to disable sysfs.


The third one is even stranger, maybe you just don’t need to crash the application?


Regarding the fourth, I can say that nothing fundamentally has changed. If specified in the platform driver or in the device tree label for gpiochip is true, then the “search” is simple, and if they are called “devils-like”, then the interface will not help here.


In general, I could not find a clear answer. I don’t mind the new interface, I’m even for it, but such diligent instillation of the old interface is incomprehensible and unpleasant for me personally.


Utilities


For uapi, they are far from being as many as for sysfs.


Linux kernel gpio tools


https://github.com/torvalds/linux/tree/master/tools/gpio



libgpiod


https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/


From the author of gpio-mockup drivers and irq-sim comrade Bartosz'a Gołaszewski.


Positioned by the author as a library, to facilitate work with gpio through the new interface uapi, also contains a set of useful utilities.



Materials


  1. GPIO Interfaces (legacy)
  2. Specifying GPIO information for devices
  3. A fresh water bottle
  4. Linus W. comment
  5. simulated interrupts
  6. GPIO bulk changes for kernel v4.6

Video


  1. GPIO for Engineers and Makers, Linus Walleij
  2. New GPIO Interface for User Space, Bartosz Golaszewski

')

Source: https://habr.com/ru/post/351512/


All Articles