xref: /illumos-gate/usr/src/test/os-tests/tests/gpio/gpioadm_test.ksh (revision fd71220ba0fafcc9cf5ea0785db206f3f31336e7)
1#!/usr/bin/ksh
2#
3#
4# This file and its contents are supplied under the terms of the
5# Common Development and Distribution License ("CDDL"), version 1.0.
6# You may only use this file in accordance with the terms of version
7# 1.0 of the CDDL.
8#
9# A full copy of the text of the CDDL should have accompanied this
10# source.  A copy of the CDDL is also available via the Internet at
11# http://www.illumos.org/license/CDDL.
12#
13
14#
15# Copyright 2022 Oxide Computer Company
16#
17
18#
19# Set up the environment with a standard locale and debugging tools to
20# help us catch failures.
21#
22export LC_ALL=C.UTF-8
23export LD_PRELOAD=libumem.so
24export UMEM_DEBUG=default
25unalias -a
26set -o pipefail
27
28gt_prog=/usr/sbin/gpioadm
29gt_arg0=$(basename $0)
30gt_data="$(dirname $0)/data"
31gt_exit=0
32gt_tmpfile="/tmp/gpioadm_test.$$"
33gt_dpio0="gpioadmtestsim00"
34gt_dpio1="gpioadmtestsim10"
35gt_dpio2="gpioadmtestsim21"
36
37warn()
38{
39        typeset msg="$*"
40        [[ -z "$msg" ]] && msg="failed"
41        echo "TEST FAILED: $msg" >&2
42	gt_exit=1
43}
44
45fatal()
46{
47        typeset msg="$*"
48        [[ -z "$msg" ]] && msg="failed"
49        echo "$sc_arg0: $msg" >&2
50        exit 1
51}
52
53cleanup()
54{
55	rm -f "$gt_tmpfile"
56}
57
58#
59# This is an invocation of gpioadm that we want to verify runs
60# successfully. We do not care about it's output, only that it exits 0.
61#
62expect_success()
63{
64	if ! $gt_prog $@ >/dev/null; then
65		warn "failed to run $@"
66	fi
67}
68
69#
70# This is an invocation of gpioadm that we want to verify exits
71# non-zero. We do not care if it is a failure or due to usage.
72#
73gpioadm_err()
74{
75	typeset reason="$1"
76	shift
77
78	if $gt_prog $@ 2>/dev/null 1>/dev/null; then
79		warn "should have failed with args "$@", but passed"
80		return
81	fi
82
83	printf "TEST PASSED: $reason: %s\n" "$*"
84}
85
86#
87# This is a case where we expect gpioadm to exit sucessfully, but we
88# want to check its exit data against a known value.
89#
90check_output()
91{
92	typeset outfile="$gt_data/$1"
93	shift
94
95	if ! $gt_prog $@ > $gt_tmpfile 2>&1; then
96		warn "$@: exited non-zero"
97	fi
98
99	if ! diff $outfile $gt_tmpfile; then
100		warn "$@: output mismatched"
101	else
102		printf "TEST PASSED: %s\n" "$*"
103	fi
104}
105
106check_dpio_link()
107{
108	typeset dpio="$1"
109
110	if [[ ! -L "/dev/dpio/$dpio" ]]; then
111		warn "missing /dev link for $dpio"
112	else
113		printf "TEST PASSED /dev link for %s present\n" "$dpio"
114	fi
115}
116
117#
118# This gets a specific GPIO's attribute value and confirm it's what we
119# expect.
120#
121check_attr_field()
122{
123	typeset gpio="$1"
124	typeset attr="$2"
125	typeset exp="$3"
126	typeset field="$4"
127	typeset out=
128
129	out=$($gt_prog gpio attr get -p -o $field $gpio $attr)
130	if (( $? != 0 )); then
131		warn "failed to gpio attr get $gpio $attr"
132		return
133	fi
134
135	if [[ "$out" != "$exp" ]]; then
136		warn "$gpio $attr has $field $out, expected $exp"
137	else
138		printf "TEST PASSED: %s %s has expected %s %s\n" "$gpio" \
139		    "$attr" "$field" "$exp"
140	fi
141}
142
143check_attr_val()
144{
145	check_attr_field $1 $2 $3 "value"
146}
147
148if [[ -n $GPIOADM ]]; then
149	gt_prog=$GPIOADM
150fi
151
152trap 'cleanup' EXIT
153
154#
155# These are a series of programs we expect to fail due to invalid
156# arguments and other variants that don't require state to be built up.
157# These are all basically bad flags, commands, or filters that don't
158# match. Other tests in the gpio test suite will go and verify the more
159# fine grained errors against libxpio directly.
160#
161gpioadm_err "bad command" foo
162gpioadm_err "bad command" foo bar
163gpioadm_err "incomplete command" controller
164gpioadm_err "bad command" controller nope
165gpioadm_err "bad command" controller wry
166gpioadm_err "bad flags" controller list -b
167gpioadm_err "parse without fields" controller list -p
168gpioadm_err "bad field" controller list -p -o itsatrap
169gpioadm_err "bad field" controller list -o itsatrap
170gpioadm_err "bad field" controller list -p -o controller,itsatrap
171gpioadm_err "unmatched filter" controller list this/doesnt/exist
172gpioadm_err "incomplete command" gpio
173gpioadm_err "bad command" gpio celes
174gpioadm_err "bad command" gpio celes terra
175gpioadm_err "bad flags" gpio list -r
176gpioadm_err "bad flags" gpio list -7
177gpioadm_err "parse without fields" gpio list -p
178gpioadm_err "bad field" gpio list -p -o 12345
179gpioadm_err "bad field" gpio list -o 12345
180gpioadm_err "bad field" gpio list -p -o name,12345
181gpioadm_err "unmatched filter" gpio list life/hopes/dreams
182gpioadm_err "unmatched filter" gpio list where do they come from
183gpioadm_err "match more than one with -1" gpio list -1
184gpioadm_err "match more than one with -1" gpio list -1 gpio_sim0
185gpioadm_err "match more than one with -1" gpio list -1 gpio_sim0 gpio_sim1
186gpioadm_err "match more than one with -1" gpio list -1 */open-drain
187gpioadm_err "match more than one with -1" gpio list -1 \
188    gpio_sim0/periodic-500ms gpio_sim1/1v8
189gpioadm_err "incomplete command" gpio attr
190gpioadm_err "bad command" gpio attr where are they going
191gpioadm_err "missing controller/gpio" gpio attr get
192gpioadm_err "bad controller/gpio" gpio attr get null
193gpioadm_err "bad controller/gpio" gpio attr get gpio_sim/3
194gpioadm_err "bad controller/gpio" gpio attr get gpio_sim0/kefka
195gpioadm_err "parse without fields" gpio attr get gpio_sim0/3 -p
196gpioadm_err "bad flags" gpio attr get -p gpio_sim0/3
197gpioadm_err "bad flags" gpio attr get -x gpio_sim0/3
198gpioadm_err "bad fields" gpio attr get -p -o frodo gpio_sim1/2
199gpioadm_err "bad fields" gpio attr get -o sam gpio_sim1/2
200gpioadm_err "bad fields" gpio attr get -p -o sim:input,frodo gpio_sim1/2
201gpioadm_err "bad filter" gpio attr get gpio_sim0/3 dusk
202gpioadm_err "bad filter" gpio attr get gpio_sim0/3 sim:pull muysterious
203gpioadm_err "missing controller/gpio" gpio attr set
204gpioadm_err "bad controller/gpio" gpio attr set gandalf
205gpioadm_err "bad controller/gpio" gpio attr set gpio_sim/1
206gpioadm_err "bad controller/gpio" gpio attr set gpio_sim0/gimli
207gpioadm_err "missing attributes" gpio attr set gpio_sim0/1
208gpioadm_err "bad flags" gpio attr set -x gpio_sim0/4 sim:output=low
209gpioadm_err "bad attribute string" gpio attr set gpio_sim0/1 foo
210gpioadm_err "bad attribute string" gpio attr set gpio_sim0/1 foo=
211gpioadm_err "bad attribute value" gpio attr set gpio_sim0/1 sim:speed=random
212gpioadm_err "bad attribute value" gpio attr set gpio_sim0/1 sim:input=0x42
213gpioadm_err "incomplete command" dpio
214gpioadm_err "bad command" dpio alchemy
215gpioadm_err "bad flags" dpio list -m
216gpioadm_err "parse without fields" dpio list -p
217gpioadm_err "bad field" dpio list -p -o sabin
218gpioadm_err "bad field" dpio list -o edgar
219gpioadm_err "bad field" dpio list -p -o edgar,sabin,controller
220gpioadm_err "unmatched filter" dpio list locke/esper
221gpioadm_err "missing operands" dpio define
222gpioadm_err "missing dpio" dpio define cloud
223gpioadm_err "missing dpio" dpio define tifa/
224gpioadm_err "missing dpio" dpio define sepiroth/7
225gpioadm_err "bad controller" dpio define cloud buster
226gpioadm_err "bad controller" dpio define tifa/ 7th
227gpioadm_err "bad controller" dpio define sepiroth/7 reunion
228gpioadm_err "bad controller" dpio define rufus/8 hq
229gpioadm_err "bad flags" dpio define -7 rufus/8 hq
230gpioadm_err "missing controller/gpio" dpio undefine
231gpioadm_err "bad controller/gpio" dpio undefine red13/
232gpioadm_err "bad controller/gpio" dpio undefine cid/2
233gpioadm_err "bad dpio name" dpio define gpio_sim/1 '-trap'
234gpioadm_err "bad dpio name" dpio define gpio_sim/1 '+foobar'
235gpioadm_err "bad dpio name" dpio define gpio_sim/1 '$nope'
236gpioadm_err "bad dpio name" dpio define gpio_sim/1 '~sorry'
237gpioadm_err "bad dpio name" dpio define gpio_sim/1 \
238    'thisisanamethatisactuallytoolongibelieve'
239gpioadm_err "bad dpio name" dpio define gpio_sim/1 'unsup()12#d'
240
241#
242# For the next set of tests we verify expected output from the various
243# listing operations with the goal of verifying that field selection,
244# parseability, omitting the header, and filtering is all working. Note,
245# we explicitly never use an unfiltered top-level list operation as we
246# have to assume that there will be something else on the system other
247# than the gpio_sim controllers that we create.
248#
249check_output "ctrl-list.out" controller list -o \
250    controller,ngpios,ndpios,provider,path gpio_sim0 gpio_sim1 gpio_sim2
251check_output "ctrl-list-H.out" controller list -H -o \
252    controller,ngpios,ndpios,provider,path gpio_sim0 gpio_sim1 gpio_sim2
253check_output "ctrl-list-p.out" controller list -p -o \
254    controller,ngpios,ndpios,provider,path gpio_sim0 gpio_sim1 gpio_sim2
255check_output "ctrl-list-sim1.out" controller list -o \
256    controller,ngpios,provider gpio_sim1
257check_output "ctrl-list-H-sim1.out" controller list -H -o \
258    controller,ngpios,provider gpio_sim1
259check_output "ctrl-list-p-sim1.out" controller list -p -o \
260    controller,ngpios,provider gpio_sim1
261check_output "gpio-period500.out" gpio list */periodic-500ms
262check_output "gpio-period500-H.out" gpio list -H */periodic-500ms
263check_output "gpio-period500-o.out" gpio list -o controller */periodic-500ms
264check_output "gpio-period500-p.out" gpio list -p -o controller */periodic-500ms
265check_output "gpio-sim0.out" gpio list gpio_sim0
266check_output "gpio-sim0-H.out" gpio list -H gpio_sim0
267check_output "gpio-sim0-o.out" gpio list -o controller gpio_sim0
268check_output "gpio-sim0-p.out" gpio list -p -o controller gpio_sim0
269check_output "gpio-sim01.out" gpio list gpio_sim0 gpio_sim1
270check_output "gpio-sim01-H.out" gpio list -H gpio_sim0 gpio_sim1
271check_output "gpio-sim01-o.out" gpio list -o controller gpio_sim0 gpio_sim1
272check_output "gpio-sim01-p.out" gpio list -p -o controller gpio_sim0 gpio_sim1
273check_output "attr-g0_0.out" gpio attr get gpio_sim0/0
274check_output "attr-g0_0-H.out" gpio attr get -H gpio_sim0/0
275check_output "attr-g0_0-o.out" gpio attr get -o attr,value,raw,possible \
276    gpio_sim0/0
277check_output "attr-g0_0-Ho.out" gpio attr get -H -o attr,value,raw,possible \
278    gpio_sim0/0
279check_output "attr-g0_0-p.out" gpio attr get -p -o attr,value,raw,possible \
280    gpio_sim0/0
281check_output "attr-g0_0_filt.out" gpio attr get -o attr,value gpio_sim0/0 \
282    name sim:pull sim:voltage
283check_output "attr-g0_0_filt-p.out" gpio attr get -p -o attr,value gpio_sim0/0 \
284    name sim:pull sim:voltage
285#
286# Repeat the above with the actual GPIO name
287#
288check_output "attr-g0_0.out" gpio attr get gpio_sim0/1v8
289check_output "attr-g0_0-H.out" gpio attr get -H gpio_sim0/1v8
290check_output "attr-g0_0-o.out" gpio attr get -o attr,value,raw,possible \
291    gpio_sim0/1v8
292check_output "attr-g0_0-Ho.out" gpio attr get -H -o attr,value,raw,possible \
293    gpio_sim0/1v8
294check_output "attr-g0_0-p.out" gpio attr get -p -o attr,value,raw,possible \
295    gpio_sim0/1v8
296check_output "attr-g0_0_filt.out" gpio attr get -o attr,value gpio_sim0/1v8 \
297    name sim:pull sim:voltage
298check_output "attr-g0_0_filt-p.out" gpio attr get -p -o attr,value \
299    gpio_sim0/1v8 name sim:pull sim:voltage
300
301#
302# To test DPIOs listing we need to actually go through and create a few
303# DPIOs. However, we also need to make sure that we leave the test with
304# these destroyed so we don't interfere with any other tests.
305#
306expect_success dpio define gpio_sim0/0 "$gt_dpio0"
307expect_success dpio define -r -w gpio_sim1/0 "$gt_dpio1"
308expect_success dpio define -r -K gpio_sim2/3v3 "$gt_dpio2"
309
310check_output "ctrl-list-dpio-p.out" controller list -p -o controller,ndpios \
311    gpio_sim0 gpio_sim1 gpio_sim2
312
313check_output "dpio.out" dpio list "$gt_dpio0" "$gt_dpio1" "$gt_dpio2"
314check_output "dpio-H.out" dpio list -H "$gt_dpio0" "$gt_dpio1" "$gt_dpio2"
315check_output "dpio-o.out" dpio list -o dpio,caps,flags,controller,gpionum \
316    "$gt_dpio0" "$gt_dpio1" "$gt_dpio2"
317check_output "dpio-Ho.out" dpio list -H -o dpio,caps,flags,controller,gpionum \
318    "$gt_dpio0" "$gt_dpio1" "$gt_dpio2"
319check_output "dpio-p.out" dpio list -p -o dpio,caps,flags,controller,gpionum \
320    "$gt_dpio0" "$gt_dpio1" "$gt_dpio2"
321
322#
323# Make sure the symlinks are installed correctly
324#
325check_dpio_link "$gt_dpio0"
326check_dpio_link "$gt_dpio1"
327check_dpio_link "$gt_dpio2"
328
329expect_success dpio undefine gpio_sim0/0
330expect_success dpio undefine gpio_sim1/0
331expect_success dpio undefine gpio_sim2/3v3
332
333#
334# Different gpio_sim gpios have different possible values and different
335# defaults. Make sure that we actually see different possible values for
336# the same attribute on different gpios and that it's not all the same.
337# Mix up the use of IDs and names.
338#
339check_attr_val gpio_sim1/1 name 3v3
340check_attr_val gpio_sim1/5 name open-drain
341check_attr_field gpio_sim1/3v3 sim:voltage 3.3V possible
342check_attr_field gpio_sim1/2 sim:voltage 12.0V possible
343check_attr_field gpio_sim1/open-drain sim:voltage 1.8V possible
344check_attr_field gpio_sim1/3 sim:pull disabled,23k-down,5k-up,40k-up possible
345check_attr_field gpio_sim1/0 sim:output disabled,low,high possible
346check_attr_field gpio_sim1/5 sim:output disabled,low possible
347check_attr_field gpio_sim1/5 sim:pull "disabled,down,up,up|down" possible
348
349#
350# Change around a few gpio sim attributes to make sure basic attribute
351# maniuplation works and then change them back.
352#
353check_attr_val gpio_sim0/3 sim:output low
354check_attr_val gpio_sim0/3 sim:pull 23k-down
355check_attr_val gpio_sim0/3 sim:input low
356expect_success gpio attr set gpio_sim0/3 sim:output=disabled sim:pull=40k-up
357check_attr_val gpio_sim0/3 sim:output disabled
358check_attr_val gpio_sim0/3 sim:pull 40k-up
359check_attr_val gpio_sim0/3 sim:input high
360expect_success gpio attr set gpio_sim0/3 sim:output=low sim:pull=23k-down
361check_attr_val gpio_sim0/3 sim:output low
362check_attr_val gpio_sim0/3 sim:pull 23k-down
363check_attr_val gpio_sim0/3 sim:input low
364
365#
366# Repeat with the name instead of the ID.
367#
368check_attr_val gpio_sim0/54V sim:output low
369check_attr_val gpio_sim0/54V sim:pull 23k-down
370check_attr_val gpio_sim0/54V sim:input low
371expect_success gpio attr set gpio_sim0/54V sim:output=disabled sim:pull=40k-up
372check_attr_val gpio_sim0/54V sim:output disabled
373check_attr_val gpio_sim0/54V sim:pull 40k-up
374check_attr_val gpio_sim0/54V sim:input high
375expect_success gpio attr set gpio_sim0/54V sim:output=low sim:pull=23k-down
376check_attr_val gpio_sim0/54V sim:output low
377check_attr_val gpio_sim0/54V sim:pull 23k-down
378check_attr_val gpio_sim0/54V sim:input low
379
380if (( gt_exit == 0 )); then
381	printf "All tests passed successfully!\n"
382fi
383