summaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/gpio/gpio-sim.sh
blob: fa2ce2b9dd5fcce1aecebfa92780141346db2cd1 (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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2021 Bartosz Golaszewski <brgl@bgdev.pl>

BASE_DIR=`dirname $0`
CONFIGFS_DIR="/sys/kernel/config/gpio-sim"
MODULE="gpio-sim"

fail() {
	echo "$*" >&2
	echo "GPIO $MODULE test FAIL"
	exit 1
}

skip() {
	echo "$*" >&2
	echo "GPIO $MODULE test SKIP"
	exit 4
}

remove_chip() {
	local CHIP=$1

	for FILE in $CONFIGFS_DIR/$CHIP/*; do
		BANK=`basename $FILE`
		if [ "$BANK" = "live" -o "$BANK" = "dev_name" ]; then
			continue
		fi

		LINES=`ls $CONFIGFS_DIR/$CHIP/$BANK/ | grep -E ^line`
		if [ "$?" = 0 ]; then
			for LINE in $LINES; do
				if [ -e $CONFIGFS_DIR/$CHIP/$BANK/$LINE/hog ]; then
					rmdir $CONFIGFS_DIR/$CHIP/$BANK/$LINE/hog || \
						fail "Unable to remove the hog"
				fi

				rmdir $CONFIGFS_DIR/$CHIP/$BANK/$LINE || \
					fail "Unable to remove the line"
			done
		fi

		rmdir $CONFIGFS_DIR/$CHIP/$BANK
	done

	rmdir $CONFIGFS_DIR/$CHIP || fail "Unable to remove the chip"
}

configfs_cleanup() {
	for CHIP in `ls $CONFIGFS_DIR/`; do
		remove_chip $CHIP
	done
}

create_chip() {
	local CHIP=$1

	mkdir $CONFIGFS_DIR/$CHIP
}

create_bank() {
	local CHIP=$1
	local BANK=$2

	mkdir $CONFIGFS_DIR/$CHIP/$BANK
}

set_label() {
	local CHIP=$1
	local BANK=$2
	local LABEL=$3

	echo $LABEL > $CONFIGFS_DIR/$CHIP/$BANK/label || fail "Unable to set the chip label"
}

set_num_lines() {
	local CHIP=$1
	local BANK=$2
	local NUM_LINES=$3

	echo $NUM_LINES > $CONFIGFS_DIR/$CHIP/$BANK/num_lines || \
		fail "Unable to set the number of lines"
}

set_line_name() {
	local CHIP=$1
	local BANK=$2
	local OFFSET=$3
	local NAME=$4
	local LINE_DIR=$CONFIGFS_DIR/$CHIP/$BANK/line$OFFSET

	test -d $LINE_DIR || mkdir $LINE_DIR
	echo $NAME > $LINE_DIR/name || fail "Unable to set the line name"
}

enable_chip() {
	local CHIP=$1

	echo 1 > $CONFIGFS_DIR/$CHIP/live || fail "Unable to enable the chip"
}

disable_chip() {
	local CHIP=$1

	echo 0 > $CONFIGFS_DIR/$CHIP/live || fail "Unable to disable the chip"
}

configfs_chip_name() {
	local CHIP=$1
	local BANK=$2

	cat $CONFIGFS_DIR/$CHIP/$BANK/chip_name 2> /dev/null || \
		fail "unable to read the chip name from configfs"
}

configfs_dev_name() {
	local CHIP=$1

	cat $CONFIGFS_DIR/$CHIP/dev_name 2> /dev/null || \
		fail "unable to read the device name from configfs"
}

get_chip_num_lines() {
	local CHIP=$1
	local BANK=$2

	$BASE_DIR/gpio-chip-info /dev/`configfs_chip_name $CHIP $BANK` num-lines || \
		fail "unable to read the number of lines from the character device"
}

get_chip_label() {
	local CHIP=$1
	local BANK=$2

	$BASE_DIR/gpio-chip-info /dev/`configfs_chip_name $CHIP $BANK` label || \
		fail "unable to read the chip label from the character device"
}

get_line_name() {
	local CHIP=$1
	local BANK=$2
	local OFFSET=$3

	$BASE_DIR/gpio-line-name /dev/`configfs_chip_name $CHIP $BANK` $OFFSET || \
		fail "unable to read the line name from the character device"
}

sysfs_set_pull() {
	local DEV=$1
	local BANK=$2
	local OFFSET=$3
	local PULL=$4
	local DEVNAME=`configfs_dev_name $DEV`
	local CHIPNAME=`configfs_chip_name $DEV $BANK`
	local SYSFSPATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio$OFFSET/pull"

	echo $PULL > $SYSFSPATH || fail "Unable to set line pull in sysfs"
}

# Load the gpio-sim module. This will pull in configfs if needed too.
modprobe gpio-sim || skip "unable to load the gpio-sim module"
# Make sure configfs is mounted at /sys/kernel/config. Wait a bit if needed.
for IDX in `seq 5`; do
	if [ "$IDX" -eq "5" ]; then
		skip "configfs not mounted at /sys/kernel/config"
	fi

	mountpoint -q /sys/kernel/config && break
	sleep 0.1
done
# If the module was already loaded: remove all previous chips
configfs_cleanup

trap "exit 1" SIGTERM SIGINT
trap configfs_cleanup EXIT

echo "1. chip_name and dev_name attributes"

echo "1.1. Chip name is communicated to user"
create_chip chip
create_bank chip bank
enable_chip chip
test -n `cat $CONFIGFS_DIR/chip/bank/chip_name` || fail "chip_name doesn't work"
remove_chip chip

echo "1.2. chip_name returns 'none' if the chip is still pending"
create_chip chip
create_bank chip bank
test "`cat $CONFIGFS_DIR/chip/bank/chip_name`" = "none" || \
	fail "chip_name doesn't return 'none' for a pending chip"
remove_chip chip

echo "1.3. Device name is communicated to user"
create_chip chip
create_bank chip bank
enable_chip chip
test -n `cat $CONFIGFS_DIR/chip/dev_name` || fail "dev_name doesn't work"
remove_chip chip

echo "2. Creating and configuring simulated chips"

echo "2.1. Default number of lines is 1"
create_chip chip
create_bank chip bank
enable_chip chip
test "`get_chip_num_lines chip bank`" = "1" || fail "default number of lines is not 1"
remove_chip chip

echo "2.2. Number of lines can be specified"
create_chip chip
create_bank chip bank
set_num_lines chip bank 16
enable_chip chip
test "`get_chip_num_lines chip bank`" = "16" || fail "number of lines is not 16"
remove_chip chip

echo "2.3. Label can be set"
create_chip chip
create_bank chip bank
set_label chip bank foobar
enable_chip chip
test "`get_chip_label chip bank`" = "foobar" || fail "label is incorrect"
remove_chip chip

echo "2.4. Label can be left empty"
create_chip chip
create_bank chip bank
enable_chip chip
test -z "`cat $CONFIGFS_DIR/chip/bank/label`" || fail "label is not empty"
remove_chip chip

echo "2.5. Line names can be configured"
create_chip chip
create_bank chip bank
set_num_lines chip bank 16
set_line_name chip bank 0 foo
set_line_name chip bank 2 bar
enable_chip chip
test "`get_line_name chip bank 0`" = "foo" || fail "line name is incorrect"
test "`get_line_name chip bank 2`" = "bar" || fail "line name is incorrect"
remove_chip chip

echo "2.6. Line config can remain unused if offset is greater than number of lines"
create_chip chip
create_bank chip bank
set_num_lines chip bank 2
set_line_name chip bank 5 foobar
enable_chip chip
test "`get_line_name chip bank 0`" = "" || fail "line name is incorrect"
test "`get_line_name chip bank 1`" = "" || fail "line name is incorrect"
remove_chip chip

echo "2.7. Line configfs directory names are sanitized"
create_chip chip
create_bank chip bank
mkdir $CONFIGFS_DIR/chip/bank/line12foobar 2> /dev/null && \
	fail "invalid configfs line name accepted"
mkdir $CONFIGFS_DIR/chip/bank/line_no_offset 2> /dev/null && \
	fail "invalid configfs line name accepted"
remove_chip chip

echo "2.8. Multiple chips can be created"
CHIPS="chip0 chip1 chip2"
for CHIP in $CHIPS; do
	create_chip $CHIP
	create_bank $CHIP bank
	enable_chip $CHIP
done
for CHIP in $CHIPS; do
	remove_chip $CHIP
done

echo "2.9. Can't modify settings when chip is live"
create_chip chip
create_bank chip bank
enable_chip chip
echo foobar > $CONFIGFS_DIR/chip/bank/label 2> /dev/null && \
	fail "Setting label of a live chip should fail"
echo 8 > $CONFIGFS_DIR/chip/bank/num_lines 2> /dev/null && \
	fail "Setting number of lines of a live chip should fail"
remove_chip chip

echo "2.10. Can't create line items when chip is live"
create_chip chip
create_bank chip bank
enable_chip chip
mkdir $CONFIGFS_DIR/chip/bank/line0 2> /dev/null && fail "Creating line item should fail"
remove_chip chip

echo "2.11. Probe errors are propagated to user-space"
create_chip chip
create_bank chip bank
set_num_lines chip bank 99999
echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Probe error was not propagated"
remove_chip chip

echo "2.12. Cannot enable a chip without any GPIO banks"
create_chip chip
echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Chip enabled without any GPIO banks"
remove_chip chip

echo "2.13. Duplicate chip labels are not allowed"
create_chip chip
create_bank chip bank0
set_label chip bank0 foobar
create_bank chip bank1
set_label chip bank1 foobar
echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Duplicate chip labels were not rejected"
remove_chip chip

echo "2.14. Lines can be hogged"
create_chip chip
create_bank chip bank
set_num_lines chip bank 8
mkdir -p $CONFIGFS_DIR/chip/bank/line4/hog
enable_chip chip
$BASE_DIR/gpio-mockup-cdev -s 1 /dev/`configfs_chip_name chip bank` 4 2> /dev/null && \
	fail "Setting the value of a hogged line shouldn't succeed"
remove_chip chip

echo "3. Controlling simulated chips"

echo "3.1. Pull can be set over sysfs"
create_chip chip
create_bank chip bank
set_num_lines chip bank 8
enable_chip chip
sysfs_set_pull chip bank 0 pull-up
$BASE_DIR/gpio-mockup-cdev /dev/`configfs_chip_name chip bank` 0
test "$?" = "1" || fail "pull set incorrectly"
sysfs_set_pull chip bank 0 pull-down
$BASE_DIR/gpio-mockup-cdev /dev/`configfs_chip_name chip bank` 1
test "$?" = "0" || fail "pull set incorrectly"
remove_chip chip

echo "3.2. Pull can be read from sysfs"
create_chip chip
create_bank chip bank
set_num_lines chip bank 8
enable_chip chip
DEVNAME=`configfs_dev_name chip`
CHIPNAME=`configfs_chip_name chip bank`
SYSFS_PATH=/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/pull
test `cat $SYSFS_PATH` = "pull-down" || fail "reading the pull failed"
sysfs_set_pull chip bank 0 pull-up
test `cat $SYSFS_PATH` = "pull-up" || fail "reading the pull failed"
remove_chip chip

echo "3.3. Incorrect input in sysfs is rejected"
create_chip chip
create_bank chip bank
set_num_lines chip bank 8
enable_chip chip
DEVNAME=`configfs_dev_name chip`
CHIPNAME=`configfs_chip_name chip bank`
SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/pull"
echo foobar > $SYSFS_PATH 2> /dev/null && fail "invalid input not detected"
remove_chip chip

echo "3.4. Can't write to value"
create_chip chip
create_bank chip bank
enable_chip chip
DEVNAME=`configfs_dev_name chip`
CHIPNAME=`configfs_chip_name chip bank`
SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value"
echo 1 > $SYSFS_PATH 2> /dev/null && fail "writing to 'value' succeeded unexpectedly"
remove_chip chip

echo "4. Simulated GPIO chips are functional"

echo "4.1. Values can be read from sysfs"
create_chip chip
create_bank chip bank
set_num_lines chip bank 8
enable_chip chip
DEVNAME=`configfs_dev_name chip`
CHIPNAME=`configfs_chip_name chip bank`
SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value"
test `cat $SYSFS_PATH` = "0" || fail "incorrect value read from sysfs"
$BASE_DIR/gpio-mockup-cdev -s 1 /dev/`configfs_chip_name chip bank` 0 &
sleep 0.1 # FIXME Any better way?
test `cat $SYSFS_PATH` = "1" || fail "incorrect value read from sysfs"
kill $!
remove_chip chip

echo "4.2. Bias settings work correctly"
create_chip chip
create_bank chip bank
set_num_lines chip bank 8
enable_chip chip
DEVNAME=`configfs_dev_name chip`
CHIPNAME=`configfs_chip_name chip bank`
SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value"
$BASE_DIR/gpio-mockup-cdev -b pull-up /dev/`configfs_chip_name chip bank` 0
test `cat $SYSFS_PATH` = "1" || fail "bias setting does not work"
remove_chip chip

echo "GPIO $MODULE test PASS"