aboutsummaryrefslogtreecommitdiff
path: root/recipes-demo/de10-nano-gpio-apps/files/README_gpio-keys.txt
blob: d5b0ac2f0e653611aa179da83edeab8e23bb0c35 (plain)
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
This readme describes the linux kernel gpio-keys framework as it deploys on the
DE10-Nano target environment.  You may find the following references useful for
more information on this topic as well.

<linux-source-tree>/Documentation/gpio/gpio.txt
<linux-source-tree>/Documentation/gpio/sysfs.txt
<linux-source-tree>/Documentation/input/input.txt
<linux-source-tree>/Documentation/input/event-codes.txt
<linux-source-tree>/Documentation/input/input-programming.txt
<linux-source-tree>/Documentation/devicetree/bindings/gpio/gpio.txt
<linux-source-tree>/Documentation/devicetree/bindings/input/gpio-keys.txt
<linux-source-tree>/Documentation/devicetree/bindings/input/gpio-keys-polled.txt

If you cut and paste the following function into a console running on the
DE10-Nano target you can extract the useful information contained in the run
time devicetree maintained by the kernel in the procfs.

################################################################################
# find gpio-keys in device tree
################################################################################
function find_gpio_keys_dt ()
{
    for NEXT in $(find -L /proc/device-tree -name "compatible" | sort);
    do
        cat ${NEXT} | grep -xz "gpio-keys" > /dev/null && {
            KEYS_DIRNAME="$(dirname ${NEXT})";
            KEYS_COMPATIBLE="$(cat ${KEYS_DIRNAME}/compatible)";
            echo "${KEYS_DIRNAME}";
            echo -e "\tcompatible = '${KEYS_COMPATIBLE}'";
            for NEXT_KEY in $(find -L "${KEYS_DIRNAME}" -name "gpios" | sort);
            do
                NEXT_KEY_DIR="$(dirname ${NEXT_KEY})";
                echo "${NEXT_KEY_DIR}";
                KEYS_GPIOS="$(hexdump -v -e '"0x" 4/1 "%02x" " "' "${NEXT_KEY}")";
                CONTROLLER_PHANDLE_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 1);
                GPIO_BIT_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 2);
                INVERTED_FLAG_HEX=$(echo ${KEYS_GPIOS} | cut -d ' ' -f 3);
                printf "             gpios = ('%d', '%d', '%d') : ('%s', '%s', '%s')\n" "${CONTROLLER_PHANDLE_HEX}" "${GPIO_BIT_HEX}" "${INVERTED_FLAG_HEX}" "controller" "bit" "flag";
                KEYS_CODE="$(hexdump -v -e '"0x" 4/1 "%02x"' "${NEXT_KEY_DIR}/linux,code")";
                printf "              code = '%d'\n" "${KEYS_CODE}";
                GPIO_CONTROLLER="unknown";
                CONTROLLER_PHANDLE_DEC="$(printf "%d" "${CONTROLLER_PHANDLE_HEX}")";
                for NEXT in $(find -L /proc/device-tree -name "phandle" | sort);
                do
                    PHANDLE_HEX="$(hexdump -v -e '"0x" 4/1 "%02x"' "${NEXT}")";
                    PHANDLE_DEC="$(printf "%d" "${PHANDLE_HEX}")";
                    [ "${PHANDLE_DEC}" -eq "${CONTROLLER_PHANDLE_DEC}" ] && {
                        GPIO_CONTROLLER="$(dirname ${NEXT})"
                    };
                done;
                printf "        controller = '%s'\n" "${GPIO_CONTROLLER}";
            done
        };
    done
}
################################################################################

The function above is provided in the file 'find_gpio_keys_dt.src', which you
can source into your environment by running 'source find_gpio_keys_dt.src'.

When we run the function above on the DE10-Nano target it searches for nodes
containing the 'compatible' string 'gpio-keys', there should be only one node
located.  The function then prints the path to the node that it found and 
extracts the 'gpios' binding and the 'linux,code' binding for each key node and
prints these statistics.

root@DE10-Nano:~# find_gpio_keys_dt
/proc/device-tree/soc/keys
        compatible = 'gpio-keys'
/proc/device-tree/soc/keys/sw0
             gpios = ('50', '0', '1') : ('controller', 'bit', 'flag')
              code = '64'
        controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000'
/proc/device-tree/soc/keys/sw1
             gpios = ('50', '1', '1') : ('controller', 'bit', 'flag')
              code = '65'
        controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000'
/proc/device-tree/soc/keys/sw2
             gpios = ('50', '2', '1') : ('controller', 'bit', 'flag')
              code = '66'
        controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000'
/proc/device-tree/soc/keys/sw3
             gpios = ('50', '3', '1') : ('controller', 'bit', 'flag')
              code = '67'
        controller = '/proc/device-tree/soc/bridge@0xc0000000/gpio@0x100004000'
root@DE10-Nano:~#

For more information on the gpio controllers framework, please read the
README_gpio.txt document.  The 'gpio@0x100004000' controller identified above
maps to the 'dipsw_pio' controller that provides a 4-bit input, fpga based gpio,
registered as 'gpio-keys' in the device tree to be used in the gpio-keys
framework to receive input events from switches SW0-SW3 on the DE10-Nano board.

The gpio-keys framework will register an input event device that will post input
events when the gpios above change their state.  The 'code' associated with each
gpio above will be encoded in the input event message along with the state of
the switch.  We can see the input device in the devfs like this:

root@DE10-Nano:~# ls -lR /dev/input
/dev/input:
total 0
drwxr-xr-x    2 root     root            80 Jul  9 16:25 by-path
crw-rw----    1 root     input      13,  64 Jan  1  1970 event0
crw-rw----    1 root     input      13,  65 Jul  9 16:25 event1
crw-rw----    1 root     input      13,  63 Jan  1  1970 mice
crw-rw----    1 root     input      13,  32 Jan  1  1970 mouse0

/dev/input/by-path:
total 0
lrwxrwxrwx    1 root     root             9 Jan  1  1970 platform-ffc04000.i2c-event -> ../event0
lrwxrwxrwx    1 root     root             9 Jul  9 16:25 platform-soc:base-fpga-region:keys-event -> ../event1

In this case the event1 device is the device for our gpio-keys input, we can
tell this from the '/dev/input/by-path' links that have more descriptive names.

The sysfs also describes the input device environment for us in a useful way.

root@DE10-Nano:~# ls -l /sys/class/input/
total 0
lrwxrwxrwx    1 root     root             0 Jan  1  1970 event0 -> ../../devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0/event0
lrwxrwxrwx    1 root     root             0 Jul 14 19:17 event1 -> ../../devices/platform/soc/soc:keys/input/input1/event1
lrwxrwxrwx    1 root     root             0 Jan  1  1970 input0 -> ../../devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0
lrwxrwxrwx    1 root     root             0 Jul 14 19:17 input1 -> ../../devices/platform/soc/soc:keys/input/input1
lrwxrwxrwx    1 root     root             0 Jan  1  1970 mice -> ../../devices/virtual/input/mice
lrwxrwxrwx    1 root     root             0 Jan  1  1970 mouse0 -> ../../devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0/mouse0

And from the above we can see that the 'soc:keys' device exists in the sysfs.

root@DE10-Nano:~# ls /sys/devices/platform/soc/soc:keys
disabled_keys      driver_override    modalias           switches
disabled_switches  input              power              uevent
driver             keys               subsystem
root@DE10-Nano:~# ls /sys/devices/platform/soc/soc:keys/input
input1
root@DE10-Nano:~# ls /sys/devices/platform/soc/soc:keys/input/input1
capabilities  event1        modalias      phys          properties    uevent
device        id            name          power         subsystem     uniq
root@DE10-Nano:~# ls /sys/devices/platform/soc/soc:keys/input/input1/event1
dev        device     power      subsystem  uevent
root@DE10-Nano:~# cat /sys/devices/platform/soc/soc:keys/input/input1/name
soc:keys
root@DE10-Nano:~# cat /sys/devices/platform/soc/soc:keys/input/input1/event1/dev
13:65
root@DE10-Nano:~# ls -l /dev/input/event1
crw-rw----    1 root     input      13,  65 Jul  9 16:25 /dev/input/event1

So now that we know what our input event device is, we can simply read from it
to capture the input events as they arrive.  The device will block until the
next event message is received.  We can do this like so:

root@DE10-Nano:~# hexdump -C /dev/input/event1
00000000  ca 61 a5 55 a4 44 08 00  01 00 40 00 00 00 00 00  |.a.U.D....@.....|
00000010  ca 61 a5 55 a4 44 08 00  00 00 00 00 00 00 00 00  |.a.U.D..........|
00000020  cc 61 a5 55 24 2a 02 00  01 00 40 00 01 00 00 00  |.a.U$*....@.....|
00000030  cc 61 a5 55 24 2a 02 00  00 00 00 00 00 00 00 00  |.a.U$*..........|
00000040  cd 61 a5 55 04 a0 0b 00  01 00 41 00 00 00 00 00  |.a.U......A.....|
00000050  cd 61 a5 55 04 a0 0b 00  00 00 00 00 00 00 00 00  |.a.U............|
00000060  cf 61 a5 55 bf 21 06 00  01 00 41 00 01 00 00 00  |.a.U.!....A.....|
00000070  cf 61 a5 55 bf 21 06 00  00 00 00 00 00 00 00 00  |.a.U.!..........|
00000080  d1 61 a5 55 7c 14 03 00  01 00 42 00 00 00 00 00  |.a.U|.....B.....|
00000090  d1 61 a5 55 7c 14 03 00  00 00 00 00 00 00 00 00  |.a.U|...........|
000000a0  d2 61 a5 55 22 2a 02 00  01 00 42 00 01 00 00 00  |.a.U"*....B.....|
000000b0  d2 61 a5 55 22 2a 02 00  00 00 00 00 00 00 00 00  |.a.U"*..........|
000000c0  d4 61 a5 55 8d ac 05 00  01 00 43 00 00 00 00 00  |.a.U......C.....|
000000d0  d4 61 a5 55 8d ac 05 00  00 00 00 00 00 00 00 00  |.a.U............|
000000e0  d7 61 a5 55 8c ac 05 00  01 00 43 00 01 00 00 00  |.a.U......C.....|
000000f0  d7 61 a5 55 8c ac 05 00  00 00 00 00 00 00 00 00  |.a.U............|
^C

The output above results after we start hexdump reading from the input event1
device, and then we toggle SW0 on and off, then we toggle SW1 on and off, then
we toggle SW2 on and off, and then we toggle SW3 on and off.  In 16 byte event
messages that appear above, we can see the first 4 bytes that represent the
second of the event, followed by the next 4 bytes that represent the millisecond
of the event, followed by the next 2 bytes that represent the event type,
followed by the next 2 bytes that represent the event code, followed by the
last 4 bytes that represent the event value.  So we can see the first line 0x00
is an EV_KEY event for SW0 with code 0x40 and value 0.  Then line 0x10 is an
EV_SYN event, followed by line 0x20 which is the next EV_KEY event for SW0 with
code 0x40 and value 1.  Then line 0x30 is another EV_SYN event.  This pattern
repeats itself for the SW1 events with code 0x41, then the SW2 events with code
0x42 and finally the SW3 events with code 0xx43.

--------------------------------------------------------------------------------
Example programs and scripts
--------------------------------------------------------------------------------
This directory contains a few examples to demonstrate how to interact with the
switches on the DE10-Nano board that have been registered in the gpio-keys
framework.  There is a shell script called 'watch_switch_events.sh' and a C
program called 'watch_switch_events.c'.  Each of these examples monitor the FPGA
gpio-keys input event in exactly the same way.  Then there is a C program called
'watch_switch_events_ioctl.c' which simply adds an ioctl() call to the
'watch_switch_events.c' program so that it can detect the current state of all
the switches, which can only be accomplished with the ioctl() call.

To build the 'watch_switch_events.c' application simply run the
'build_watch_switch_events.sh' shell script.  That will compile the
'watch_switch_events.c' source file and produce the executable
'watch_switch_events' application.  Refer to the 'build_watch_switch_events.sh'
script to see how the application is actually compiled and refer to the C
program source file for more details on how it actually works.

To build the 'watch_switch_events_ioctl.c' application simply run the
'build_watch_switch_events_ioctl.sh' shell script.  That will compile the
'watch_switch_events_ioctl.c' source file and produce the executable
'watch_switch_events_ioctl' application.  Refer to the
'build_watch_switch_events_ioctl.sh' script to see how the application is
actually compiled and refer to the C program source file for more details on how
it actually works.

Refer to the 'watch_switch_events.sh' source file for more details on how it
actually works.

Once you've built the applications, you can run both the script and the
applications like this:

./watch_switch_events.sh	<<< to run the script
./watch_switch_events		<<< to run the program
./watch_switch_events_ioctl	<<< to run the program with ioctl()

The programs and script will monitor the input events for the gpio-keys device
registered in the system.  To generate an input event slide the switches SW0,
SW1, SW2 and SW3 on the DE10-Nano board.  As you slide the switches you will see
the programs and script print out the input events that they receive from the
system.  The ioctl version of the program will additionally print out the
current state of all the switches at each input event as well.  To terminate the
script or programs just type CTRL-C on the console that you launched them from.

Both the programs and the script monitor the switches by interacting with the
input event device node provided by the gpio-keys framework which leverages the
linux gpio controller framework.