Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/gpio/gpio-mockup.sh
26285 views
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
9
BASE=${0%/*}
10
DEBUGFS=
11
GPIO_DEBUGFS=
12
dev_type="cdev"
13
module="gpio-mockup"
14
verbose=
15
full_test=
16
random=
17
uapi_opt=
18
active_opt=
19
bias_opt=
20
line_set_pid=
21
22
# Kselftest return codes
23
ksft_fail=1
24
ksft_skip=4
25
26
usage()
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
40
skip()
41
{
42
echo "$*" >&2
43
echo "GPIO $module test SKIP"
44
exit $ksft_skip
45
}
46
47
prerequisite()
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
57
remove_module()
58
{
59
modprobe -r -q $module
60
}
61
62
cleanup()
63
{
64
set +e
65
release_line
66
remove_module
67
jobs -p | xargs -r kill > /dev/null 2>&1
68
}
69
70
fail()
71
{
72
echo "test failed: $*" >&2
73
echo "GPIO $module test FAIL"
74
exit $ksft_fail
75
}
76
77
try_insert_module()
78
{
79
modprobe -q $module "$1" || fail "insert $module failed with error $?"
80
}
81
82
log()
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
94
release_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
101
get_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.
115
set_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
162
assert_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
171
assert_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
187
set_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).
202
test_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
268
test_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.
286
insmod_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
313
while 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
331
done
332
shift $((OPTIND - 1))
333
334
[ "${1:-}" ] && fail "unknown argument '$1'"
335
336
prerequisite
337
338
trap 'exit $ksft_fail' SIGTERM SIGINT
339
trap cleanup EXIT
340
341
case "$dev_type" in
342
sysfs)
343
source $BASE/gpio-mockup-sysfs.sh
344
echo "WARNING: gpio sysfs ABI is deprecated."
345
;;
346
cdev_v1)
347
echo "WARNING: gpio cdev ABI v1 is deprecated."
348
uapi_opt="-u1 "
349
;;
350
cdev)
351
;;
352
*)
353
fail "unknown interface type: $dev_type"
354
;;
355
esac
356
357
remove_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
362
echo "1. Module load tests"
363
echo "1.1. dynamic allocation of gpio"
364
insmod_test "-1,32" 32
365
insmod_test "-1,23,-1,32" 23 32
366
insmod_test "-1,23,-1,26,-1,32" 23 26 32
367
if [ "$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
378
fi
379
echo "2. Module load error tests"
380
echo "2.1 no lines defined"
381
insmod_test "0,0"
382
if [ "$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
398
fi
399
400
echo "GPIO $module test PASS"
401
402