Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/bin/bash -efu
2# SPDX-License-Identifier: GPL-2.0
3
4#exit status
5#0: success
6#1: fail
7#4: skip test - including run as non-root user
8
9BASE=${0%/*}
10DEBUGFS=
11GPIO_DEBUGFS=
12dev_type="cdev"
13module="gpio-mockup"
14verbose=
15full_test=
16random=
17uapi_opt=
18active_opt=
19bias_opt=
20line_set_pid=
21
22# Kselftest return codes
23ksft_fail=1
24ksft_skip=4
25
26usage()
27{
28 echo "Usage:"
29 echo "$0 [-frv] [-t type]"
30 echo "-f: full test (minimal set run by default)"
31 echo "-r: test random lines as well as fence posts"
32 echo "-t: interface type:"
33 echo " cdev (character device ABI) - default"
34 echo " cdev_v1 (deprecated character device ABI)"
35 echo " sysfs (deprecated SYSFS ABI)"
36 echo "-v: verbose progress reporting"
37 exit $ksft_fail
38}
39
40skip()
41{
42 echo "$*" >&2
43 echo "GPIO $module test SKIP"
44 exit $ksft_skip
45}
46
47prerequisite()
48{
49 [ $(id -u) -eq 0 ] || skip "must be run as root"
50
51 DEBUGFS=$(grep -w debugfs /proc/mounts | cut -f2 -d' ')
52 [ -d "$DEBUGFS" ] || skip "debugfs is not mounted"
53
54 GPIO_DEBUGFS=$DEBUGFS/$module
55}
56
57remove_module()
58{
59 modprobe -r -q $module
60}
61
62cleanup()
63{
64 set +e
65 release_line
66 remove_module
67 jobs -p | xargs -r kill > /dev/null 2>&1
68}
69
70fail()
71{
72 echo "test failed: $*" >&2
73 echo "GPIO $module test FAIL"
74 exit $ksft_fail
75}
76
77try_insert_module()
78{
79 modprobe -q $module "$1" || fail "insert $module failed with error $?"
80}
81
82log()
83{
84 [ -z "$verbose" ] || echo "$*"
85}
86
87# The following line helpers, release_Line, get_line and set_line, all
88# make use of the global $chip and $offset variables.
89#
90# This implementation drives the GPIO character device (cdev) uAPI.
91# Other implementations may override these to test different uAPIs.
92
93# Release any resources related to the line
94release_line()
95{
96 [ "$line_set_pid" ] && kill $line_set_pid && wait $line_set_pid || true
97 line_set_pid=
98}
99
100# Read the current value of the line
101get_line()
102{
103 release_line
104
105 local cdev_opts=${uapi_opt}${active_opt}
106 $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset
107 echo $?
108}
109
110# Set the state of the line
111#
112# Changes to line configuration are provided as parameters.
113# The line is assumed to be an output if the line value 0 or 1 is
114# specified, else an input.
115set_line()
116{
117 local val=
118
119 release_line
120
121 # parse config options...
122 for option in $*; do
123 case $option in
124 active-low)
125 active_opt="-l "
126 ;;
127 active-high)
128 active_opt=
129 ;;
130 bias-none)
131 bias_opt=
132 ;;
133 pull-down)
134 bias_opt="-bpull-down "
135 ;;
136 pull-up)
137 bias_opt="-bpull-up "
138 ;;
139 0)
140 val=0
141 ;;
142 1)
143 val=1
144 ;;
145 esac
146 done
147
148 local cdev_opts=${uapi_opt}${active_opt}
149 if [ "$val" ]; then
150 $BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset &
151 # failure to set is detected by reading mockup and toggling values
152 line_set_pid=$!
153 # allow for gpio-mockup-cdev to launch and request line
154 # (there is limited value in checking if line has been requested)
155 sleep 0.01
156 elif [ "$bias_opt" ]; then
157 cdev_opts=${cdev_opts}${bias_opt}
158 $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset || true
159 fi
160}
161
162assert_line()
163{
164 local val
165 # don't need any retry here as set_mock allows for propagation
166 val=$(get_line)
167 [ "$val" = "$1" ] || fail "line value is ${val:-empty} when $1 was expected"
168}
169
170# The following mockup helpers all make use of the $mock_line
171assert_mock()
172{
173 local backoff_wait=10
174 local retry=0
175 local val
176 # retry allows for set propagation from uAPI to mockup
177 while true; do
178 val=$(< $mock_line)
179 [ "$val" = "$1" ] && break
180 retry=$((retry + 1))
181 [ $retry -lt 5 ] || fail "mockup $mock_line value ${val:-empty} when $1 expected"
182 sleep $(printf "%0.2f" $((backoff_wait))e-3)
183 backoff_wait=$((backoff_wait * 2))
184 done
185}
186
187set_mock()
188{
189 echo "$1" > $mock_line
190 # allow for set propagation - so we won't be in a race with set_line
191 assert_mock "$1"
192}
193
194# test the functionality of a line
195#
196# The line is set from the mockup side and is read from the userspace side
197# (input), and is set from the userspace side and is read from the mockup side
198# (output).
199#
200# Setting the mockup pull using the userspace interface bias settings is
201# tested where supported by the userspace interface (cdev).
202test_line()
203{
204 chip=$1
205 offset=$2
206 log "test_line $chip $offset"
207 mock_line=$GPIO_DEBUGFS/$chip/$offset
208 [ -e "$mock_line" ] || fail "missing line $chip:$offset"
209
210 # test input active-high
211 set_mock 1
212 set_line input active-high
213 assert_line 1
214 set_mock 0
215 assert_line 0
216 set_mock 1
217 assert_line 1
218
219 if [ "$full_test" ]; then
220 if [ "$dev_type" != "sysfs" ]; then
221 # test pulls
222 set_mock 0
223 set_line input pull-up
224 assert_line 1
225 set_mock 0
226 assert_line 0
227
228 set_mock 1
229 set_line input pull-down
230 assert_line 0
231 set_mock 1
232 assert_line 1
233
234 set_line bias-none
235 fi
236
237 # test input active-low
238 set_mock 0
239 set_line active-low
240 assert_line 1
241 set_mock 1
242 assert_line 0
243 set_mock 0
244 assert_line 1
245
246 # test output active-high
247 set_mock 1
248 set_line active-high 0
249 assert_mock 0
250 set_line 1
251 assert_mock 1
252 set_line 0
253 assert_mock 0
254 fi
255
256 # test output active-low
257 set_mock 0
258 set_line active-low 0
259 assert_mock 1
260 set_line 1
261 assert_mock 0
262 set_line 0
263 assert_mock 1
264
265 release_line
266}
267
268test_no_line()
269{
270 log test_no_line "$*"
271 [ ! -e "$GPIO_DEBUGFS/$1/$2" ] || fail "unexpected line $1:$2"
272}
273
274# Load the module and check that the expected number of gpiochips, with the
275# expected number of lines, are created and are functional.
276#
277# $1 is the gpio_mockup_ranges parameter for the module
278# The remaining parameters are the number of lines, n, expected for each of
279# the gpiochips expected to be created.
280#
281# For each gpiochip the fence post lines, 0 and n-1, are tested, and the
282# line on the far side of the fence post, n, is tested to not exist.
283#
284# If the $random flag is set then a random line in the middle of the
285# gpiochip is tested as well.
286insmod_test()
287{
288 local ranges=
289 local gc=
290 local width=
291
292 [ "${1:-}" ] || fail "missing ranges"
293 ranges=$1 ; shift
294 try_insert_module "gpio_mockup_ranges=$ranges"
295 log "GPIO $module test with ranges: <$ranges>:"
296 # e.g. /sys/kernel/debug/gpio-mockup/gpiochip1
297 gpiochip=$(find "$DEBUGFS/$module/" -name gpiochip* -type d | sort)
298 for chip in $gpiochip; do
299 gc=${chip##*/}
300 [ "${1:-}" ] || fail "unexpected chip - $gc"
301 width=$1 ; shift
302 test_line $gc 0
303 if [ "$random" -a $width -gt 2 ]; then
304 test_line $gc $((RANDOM % ($width - 2) + 1))
305 fi
306 test_line $gc $(($width - 1))
307 test_no_line $gc $width
308 done
309 [ "${1:-}" ] && fail "missing expected chip of width $1"
310 remove_module || fail "failed to remove module with error $?"
311}
312
313while getopts ":frvt:" opt; do
314 case $opt in
315 f)
316 full_test=true
317 ;;
318 r)
319 random=true
320 ;;
321 t)
322 dev_type=$OPTARG
323 ;;
324 v)
325 verbose=true
326 ;;
327 *)
328 usage
329 ;;
330 esac
331done
332shift $((OPTIND - 1))
333
334[ "${1:-}" ] && fail "unknown argument '$1'"
335
336prerequisite
337
338trap 'exit $ksft_fail' SIGTERM SIGINT
339trap cleanup EXIT
340
341case "$dev_type" in
342sysfs)
343 source $BASE/gpio-mockup-sysfs.sh
344 echo "WARNING: gpio sysfs ABI is deprecated."
345 ;;
346cdev_v1)
347 echo "WARNING: gpio cdev ABI v1 is deprecated."
348 uapi_opt="-u1 "
349 ;;
350cdev)
351 ;;
352*)
353 fail "unknown interface type: $dev_type"
354 ;;
355esac
356
357remove_module || fail "can't remove existing $module module"
358
359# manual gpio allocation tests fail if a physical chip already exists
360[ "$full_test" -a -e "/dev/gpiochip0" ] && skip "full tests conflict with gpiochip0"
361
362echo "1. Module load tests"
363echo "1.1. dynamic allocation of gpio"
364insmod_test "-1,32" 32
365insmod_test "-1,23,-1,32" 23 32
366insmod_test "-1,23,-1,26,-1,32" 23 26 32
367if [ "$full_test" ]; then
368 echo "1.2. manual allocation of gpio"
369 insmod_test "0,32" 32
370 insmod_test "0,32,32,60" 32 28
371 insmod_test "0,32,40,64,64,96" 32 24 32
372 echo "1.3. dynamic and manual allocation of gpio"
373 insmod_test "-1,32,32,62" 32 30
374 insmod_test "-1,22,-1,23,0,24,32,64" 22 23 24 32
375 insmod_test "-1,32,32,60,-1,29" 32 28 29
376 insmod_test "-1,32,40,64,-1,5" 32 24 5
377 insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31
378fi
379echo "2. Module load error tests"
380echo "2.1 no lines defined"
381insmod_test "0,0"
382if [ "$full_test" ]; then
383 echo "2.2 ignore range overlap"
384 insmod_test "0,32,0,1" 32
385 insmod_test "0,32,1,5" 32
386 insmod_test "0,32,30,35" 32
387 insmod_test "0,32,31,32" 32
388 insmod_test "10,32,30,35" 22
389 insmod_test "10,32,9,14" 22
390 insmod_test "0,32,20,21,40,56" 32 16
391 insmod_test "0,32,32,64,32,40" 32 32
392 insmod_test "0,32,32,64,36,37" 32 32
393 insmod_test "0,32,35,64,34,36" 32 29
394 insmod_test "0,30,35,64,35,45" 30 29
395 insmod_test "0,32,40,56,30,33" 32 16
396 insmod_test "0,32,40,56,30,41" 32 16
397 insmod_test "0,32,40,56,39,45" 32 16
398fi
399
400echo "GPIO $module test PASS"