1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
.. SPDX-License-Identifier: GPL-2.0-only
GPIO Aggregator
===============
The GPIO Aggregator provides a mechanism to aggregate GPIOs, and expose them as
a new gpio_chip. This supports the following use cases.
Aggregating GPIOs using Sysfs
-----------------------------
GPIO controllers are exported to userspace using /dev/gpiochip* character
devices. Access control to these devices is provided by standard UNIX file
system permissions, on an all-or-nothing basis: either a GPIO controller is
accessible for a user, or it is not.
The GPIO Aggregator provides access control for a set of one or more GPIOs, by
aggregating them into a new gpio_chip, which can be assigned to a group or user
using standard UNIX file ownership and permissions. Furthermore, this
simplifies and hardens exporting GPIOs to a virtual machine, as the VM can just
grab the full GPIO controller, and no longer needs to care about which GPIOs to
grab and which not, reducing the attack surface.
Aggregated GPIO controllers are instantiated and destroyed by writing to
write-only attribute files in sysfs.
/sys/bus/platform/drivers/gpio-aggregator/
"new_device" ...
Userspace may ask the kernel to instantiate an aggregated GPIO
controller by writing a string describing the GPIOs to
aggregate to the "new_device" file, using the format
.. code-block:: none
[<gpioA>] [<gpiochipB> <offsets>] ...
Where:
"<gpioA>" ...
is a GPIO line name,
"<gpiochipB>" ...
is a GPIO chip label, and
"<offsets>" ...
is a comma-separated list of GPIO offsets and/or
GPIO offset ranges denoted by dashes.
Example: Instantiate a new GPIO aggregator by aggregating GPIO
line 19 of "e6052000.gpio" and GPIO lines 20-21 of
"e6050000.gpio" into a new gpio_chip:
.. code-block:: sh
$ echo 'e6052000.gpio 19 e6050000.gpio 20-21' > new_device
"delete_device" ...
Userspace may ask the kernel to destroy an aggregated GPIO
controller after use by writing its device name to the
"delete_device" file.
Example: Destroy the previously-created aggregated GPIO
controller, assumed to be "gpio-aggregator.0":
.. code-block:: sh
$ echo gpio-aggregator.0 > delete_device
Aggregating GPIOs using Configfs
--------------------------------
**Group:** ``/config/gpio-aggregator``
This is the root directory of the gpio-aggregator configfs tree.
**Group:** ``/config/gpio-aggregator/<example-name>``
This directory represents a GPIO aggregator device. You can assign any
name to ``<example-name>`` (e.g. ``agg0``), except names starting with
``_sysfs`` prefix, which are reserved for auto-generated configfs
entries corresponding to devices created via Sysfs.
**Attribute:** ``/config/gpio-aggregator/<example-name>/live``
The ``live`` attribute allows to trigger the actual creation of the device
once it's fully configured. Accepted values are:
* ``1``, ``yes``, ``true`` : enable the virtual device
* ``0``, ``no``, ``false`` : disable the virtual device
**Attribute:** ``/config/gpio-aggregator/<example-name>/dev_name``
The read-only ``dev_name`` attribute exposes the name of the device as it
will appear in the system on the platform bus (e.g. ``gpio-aggregator.0``).
This is useful for identifying a character device for the newly created
aggregator. If it's ``gpio-aggregator.0``,
``/sys/devices/platform/gpio-aggregator.0/gpiochipX`` path tells you that the
GPIO device id is ``X``.
You must create subdirectories for each virtual line you want to
instantiate, named exactly as ``line0``, ``line1``, ..., ``lineY``, when
you want to instantiate ``Y+1`` (Y >= 0) lines. Configure all lines before
activating the device by setting ``live`` to 1.
**Group:** ``/config/gpio-aggregator/<example-name>/<lineY>/``
This directory represents a GPIO line to include in the aggregator.
**Attribute:** ``/config/gpio-aggregator/<example-name>/<lineY>/key``
**Attribute:** ``/config/gpio-aggregator/<example-name>/<lineY>/offset``
The default values after creating the ``<lineY>`` directory are:
* ``key`` : <empty>
* ``offset`` : -1
``key`` must always be explicitly configured, while ``offset`` depends.
Two configuration patterns exist for each ``<lineY>``:
(a). For lookup by GPIO line name:
* Set ``key`` to the line name.
* Ensure ``offset`` remains -1 (the default).
(b). For lookup by GPIO chip name and the line offset within the chip:
* Set ``key`` to the chip name.
* Set ``offset`` to the line offset (0 <= ``offset`` < 65535).
**Attribute:** ``/config/gpio-aggregator/<example-name>/<lineY>/name``
The ``name`` attribute sets a custom name for lineY. If left unset, the
line will remain unnamed.
Once the configuration is done, the ``'live'`` attribute must be set to 1
in order to instantiate the aggregator device. It can be set back to 0 to
destroy the virtual device. The module will synchronously wait for the new
aggregator device to be successfully probed and if this doesn't happen, writing
to ``'live'`` will result in an error. This is a different behaviour from the
case when you create it using sysfs ``new_device`` interface.
.. note::
For aggregators created via Sysfs, the configfs entries are
auto-generated and appear as ``/config/gpio-aggregator/_sysfs.<N>/``. You
cannot add or remove line directories with mkdir(2)/rmdir(2). To modify
lines, you must use the "delete_device" interface to tear down the
existing device and reconfigure it from scratch. However, you can still
toggle the aggregator with the ``live`` attribute and adjust the
``key``, ``offset``, and ``name`` attributes for each line when ``live``
is set to 0 by hand (i.e. it's not waiting for deferred probe).
Sample configuration commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: sh
# Create a directory for an aggregator device
$ mkdir /sys/kernel/config/gpio-aggregator/agg0
# Configure each line
$ mkdir /sys/kernel/config/gpio-aggregator/agg0/line0
$ echo gpiochip0 > /sys/kernel/config/gpio-aggregator/agg0/line0/key
$ echo 6 > /sys/kernel/config/gpio-aggregator/agg0/line0/offset
$ echo test0 > /sys/kernel/config/gpio-aggregator/agg0/line0/name
$ mkdir /sys/kernel/config/gpio-aggregator/agg0/line1
$ echo gpiochip0 > /sys/kernel/config/gpio-aggregator/agg0/line1/key
$ echo 7 > /sys/kernel/config/gpio-aggregator/agg0/line1/offset
$ echo test1 > /sys/kernel/config/gpio-aggregator/agg0/line1/name
# Activate the aggregator device
$ echo 1 > /sys/kernel/config/gpio-aggregator/agg0/live
Generic GPIO Driver
-------------------
The GPIO Aggregator can also be used as a generic driver for a simple
GPIO-operated device described in DT, without a dedicated in-kernel driver.
This is useful in industrial control, and is not unlike e.g. spidev, which
allows the user to communicate with an SPI device from userspace.
Binding a device to the GPIO Aggregator is performed either by modifying the
gpio-aggregator driver, or by writing to the "driver_override" file in Sysfs.
Example: If "door" is a GPIO-operated device described in DT, using its own
compatible value::
door {
compatible = "myvendor,mydoor";
gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>,
<&gpio2 20 GPIO_ACTIVE_LOW>;
gpio-line-names = "open", "lock";
};
it can be bound to the GPIO Aggregator by either:
1. Adding its compatible value to ``gpio_aggregator_dt_ids[]``,
2. Binding manually using "driver_override":
.. code-block:: sh
$ echo gpio-aggregator > /sys/bus/platform/devices/door/driver_override
$ echo door > /sys/bus/platform/drivers/gpio-aggregator/bind
After that, a new gpiochip "door" has been created:
.. code-block:: sh
$ gpioinfo door
gpiochip12 - 2 lines:
line 0: "open" unused input active-high
line 1: "lock" unused input active-high
|