mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	 10f33652c0
			
		
	
	
		10f33652c0
		
	
	
	
	
		
			
			Add a port to the GPIO uAPI v2 interface and make it the default. Signed-off-by: Kent Gibson <warthog618@gmail.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
		
			
				
	
	
		
			404 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			404 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/bash -efu
 | |
| # SPDX-License-Identifier: GPL-2.0
 | |
| 
 | |
| #exit status
 | |
| #0: success
 | |
| #1: fail
 | |
| #4: skip test - including run as non-root user
 | |
| 
 | |
| BASE=${0%/*}
 | |
| DEBUGFS=
 | |
| GPIO_DEBUGFS=
 | |
| dev_type="cdev"
 | |
| module="gpio-mockup"
 | |
| verbose=
 | |
| full_test=
 | |
| random=
 | |
| uapi_opt=
 | |
| active_opt=
 | |
| bias_opt=
 | |
| line_set_pid=
 | |
| 
 | |
| # Kselftest return codes
 | |
| ksft_fail=1
 | |
| ksft_skip=4
 | |
| 
 | |
| usage()
 | |
| {
 | |
| 	echo "Usage:"
 | |
| 	echo "$0 [-frv] [-t type]"
 | |
| 	echo "-f:  full test (minimal set run by default)"
 | |
| 	echo "-r:  test random lines as well as fence posts"
 | |
| 	echo "-t:  interface type:"
 | |
| 	echo "      cdev (character device ABI) - default"
 | |
| 	echo "      cdev_v1 (deprecated character device ABI)"
 | |
| 	echo "      sysfs (deprecated SYSFS ABI)"
 | |
| 	echo "-v:  verbose progress reporting"
 | |
| 	exit $ksft_fail
 | |
| }
 | |
| 
 | |
| skip()
 | |
| {
 | |
| 	echo "$*" >&2
 | |
| 	echo "GPIO $module test SKIP"
 | |
| 	exit $ksft_skip
 | |
| }
 | |
| 
 | |
| prerequisite()
 | |
| {
 | |
| 	[ $(id -u) -eq 0 ] || skip "must be run as root"
 | |
| 
 | |
| 	DEBUGFS=$(grep -w debugfs /proc/mounts | cut -f2 -d' ')
 | |
| 	[ -d "$DEBUGFS" ] || skip "debugfs is not mounted"
 | |
| 
 | |
| 	GPIO_DEBUGFS=$DEBUGFS/$module
 | |
| }
 | |
| 
 | |
| remove_module()
 | |
| {
 | |
| 	modprobe -r -q $module
 | |
| }
 | |
| 
 | |
| cleanup()
 | |
| {
 | |
| 	set +e
 | |
| 	release_line
 | |
| 	remove_module
 | |
| 	jobs -p | xargs -r kill > /dev/null 2>&1
 | |
| }
 | |
| 
 | |
| fail()
 | |
| {
 | |
| 	echo "test failed: $*" >&2
 | |
| 	echo "GPIO $module test FAIL"
 | |
| 	exit $ksft_fail
 | |
| }
 | |
| 
 | |
| try_insert_module()
 | |
| {
 | |
| 	modprobe -q $module "$1" || fail "insert $module failed with error $?"
 | |
| }
 | |
| 
 | |
| log()
 | |
| {
 | |
| 	[ -z "$verbose" ] || echo "$*"
 | |
| }
 | |
| 
 | |
| # The following line helpers, release_Line, get_line and set_line, all
 | |
| # make use of the global $chip and $offset variables.
 | |
| #
 | |
| # This implementation drives the GPIO character device (cdev) uAPI.
 | |
| # Other implementations may override these to test different uAPIs.
 | |
| 
 | |
| # Release any resources related to the line
 | |
| release_line()
 | |
| {
 | |
| 	[ "$line_set_pid" ] && kill $line_set_pid && wait $line_set_pid || true
 | |
| 	line_set_pid=
 | |
| }
 | |
| 
 | |
| # Read the current value of the line
 | |
| get_line()
 | |
| {
 | |
| 	release_line
 | |
| 
 | |
| 	local cdev_opts=${uapi_opt}${active_opt}
 | |
| 	$BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset
 | |
| 	echo $?
 | |
| }
 | |
| 
 | |
| # Set the state of the line
 | |
| #
 | |
| # Changes to line configuration are provided as parameters.
 | |
| # The line is assumed to be an output if the line value 0 or 1 is
 | |
| # specified, else an input.
 | |
| set_line()
 | |
| {
 | |
| 	local val=
 | |
| 
 | |
| 	release_line
 | |
| 
 | |
| 	# parse config options...
 | |
| 	for option in $*; do
 | |
| 		case $option in
 | |
| 		active-low)
 | |
| 			active_opt="-l "
 | |
| 			;;
 | |
| 		active-high)
 | |
| 			active_opt=
 | |
| 			;;
 | |
| 		bias-none)
 | |
| 			bias_opt=
 | |
| 			;;
 | |
| 		pull-down)
 | |
| 			bias_opt="-bpull-down "
 | |
| 			;;
 | |
| 		pull-up)
 | |
| 			bias_opt="-bpull-up "
 | |
| 			;;
 | |
| 		0)
 | |
| 			val=0
 | |
| 			;;
 | |
| 		1)
 | |
| 			val=1
 | |
| 			;;
 | |
| 		esac
 | |
| 	done
 | |
| 
 | |
| 	local cdev_opts=${uapi_opt}${active_opt}
 | |
| 	if [ "$val" ]; then
 | |
| 		$BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset &
 | |
| 		# failure to set is detected by reading mockup and toggling values
 | |
| 		line_set_pid=$!
 | |
| 		# allow for gpio-mockup-cdev to launch and request line
 | |
| 		# (there is limited value in checking if line has been requested)
 | |
| 		sleep 0.01
 | |
| 	elif [ "$bias_opt" ]; then
 | |
| 		cdev_opts=${cdev_opts}${bias_opt}
 | |
| 		$BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset || true
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| assert_line()
 | |
| {
 | |
| 	local val
 | |
| 	# don't need any retry here as set_mock allows for propagation
 | |
| 	val=$(get_line)
 | |
| 	[ "$val" = "$1" ] || fail "line value is ${val:-empty} when $1 was expected"
 | |
| }
 | |
| 
 | |
| # The following mockup helpers all make use of the $mock_line
 | |
| assert_mock()
 | |
| {
 | |
| 	local backoff_wait=10
 | |
| 	local retry=0
 | |
| 	local val
 | |
| 	# retry allows for set propagation from uAPI to mockup
 | |
| 	while true; do
 | |
| 		val=$(< $mock_line)
 | |
| 		[ "$val" = "$1" ] && break
 | |
| 		retry=$((retry + 1))
 | |
| 		[ $retry -lt 5 ] || fail "mockup $mock_line value ${val:-empty} when $1 expected"
 | |
| 		sleep $(printf "%0.2f" $((backoff_wait))e-3)
 | |
| 		backoff_wait=$((backoff_wait * 2))
 | |
| 	done
 | |
| }
 | |
| 
 | |
| set_mock()
 | |
| {
 | |
| 	echo "$1" > $mock_line
 | |
| 	# allow for set propagation - so we won't be in a race with set_line
 | |
| 	assert_mock "$1"
 | |
| }
 | |
| 
 | |
| # test the functionality of a line
 | |
| #
 | |
| # The line is set from the mockup side and is read from the userspace side
 | |
| # (input), and is set from the userspace side and is read from the mockup side
 | |
| # (output).
 | |
| #
 | |
| # Setting the mockup pull using the userspace interface bias settings is
 | |
| # tested where supported by the userspace interface (cdev).
 | |
| test_line()
 | |
| {
 | |
| 	chip=$1
 | |
| 	offset=$2
 | |
| 	log "test_line $chip $offset"
 | |
| 	mock_line=$GPIO_DEBUGFS/$chip/$offset
 | |
| 	[ -e "$mock_line" ] || fail "missing line $chip:$offset"
 | |
| 
 | |
| 	# test input active-high
 | |
| 	set_mock 1
 | |
| 	set_line input active-high
 | |
| 	assert_line 1
 | |
| 	set_mock 0
 | |
| 	assert_line 0
 | |
| 	set_mock 1
 | |
| 	assert_line 1
 | |
| 
 | |
| 	if [ "$full_test" ]; then
 | |
| 		if [ "$dev_type" != "sysfs" ]; then
 | |
| 			# test pulls
 | |
| 			set_mock 0
 | |
| 			set_line input pull-up
 | |
| 			assert_line 1
 | |
| 			set_mock 0
 | |
| 			assert_line 0
 | |
| 
 | |
| 			set_mock 1
 | |
| 			set_line input pull-down
 | |
| 			assert_line 0
 | |
| 			set_mock 1
 | |
| 			assert_line 1
 | |
| 
 | |
| 			set_line bias-none
 | |
| 		fi
 | |
| 
 | |
| 		# test input active-low
 | |
| 		set_mock 0
 | |
| 		set_line active-low
 | |
| 		assert_line 1
 | |
| 		set_mock 1
 | |
| 		assert_line 0
 | |
| 		set_mock 0
 | |
| 		assert_line 1
 | |
| 
 | |
| 		# test output active-high
 | |
| 		set_mock 1
 | |
| 		set_line active-high 0
 | |
| 		assert_mock 0
 | |
| 		set_line 1
 | |
| 		assert_mock 1
 | |
| 		set_line 0
 | |
| 		assert_mock 0
 | |
| 	fi
 | |
| 
 | |
| 	# test output active-low
 | |
| 	set_mock 0
 | |
| 	set_line active-low 0
 | |
| 	assert_mock 1
 | |
| 	set_line 1
 | |
| 	assert_mock 0
 | |
| 	set_line 0
 | |
| 	assert_mock 1
 | |
| 
 | |
| 	release_line
 | |
| }
 | |
| 
 | |
| test_no_line()
 | |
| {
 | |
| 	log test_no_line "$*"
 | |
| 	[ ! -e "$GPIO_DEBUGFS/$1/$2" ] || fail "unexpected line $1:$2"
 | |
| }
 | |
| 
 | |
| # Load the module and check that the expected number of gpiochips, with the
 | |
| # expected number of lines, are created and are functional.
 | |
| #
 | |
| # $1 is the gpio_mockup_ranges parameter for the module
 | |
| # The remaining parameters are the number of lines, n, expected for each of
 | |
| # the gpiochips expected to be created.
 | |
| #
 | |
| # For each gpiochip the fence post lines, 0 and n-1, are tested, and the
 | |
| # line on the far side of the fence post, n, is tested to not exist.
 | |
| #
 | |
| # If the $random flag is set then a random line in the middle of the
 | |
| # gpiochip is tested as well.
 | |
| insmod_test()
 | |
| {
 | |
| 	local ranges=
 | |
| 	local gc=
 | |
| 	local width=
 | |
| 
 | |
| 	[ "${1:-}" ] || fail "missing ranges"
 | |
| 	ranges=$1 ; shift
 | |
| 	try_insert_module "gpio_mockup_ranges=$ranges"
 | |
| 	log "GPIO $module test with ranges: <$ranges>:"
 | |
| 	# e.g. /sys/kernel/debug/gpio-mockup/gpiochip1
 | |
| 	gpiochip=$(find "$DEBUGFS/$module/" -name gpiochip* -type d | sort)
 | |
| 	for chip in $gpiochip; do
 | |
| 		gc=${chip##*/}
 | |
| 		[ "${1:-}" ] || fail "unexpected chip - $gc"
 | |
| 		width=$1 ; shift
 | |
| 		test_line $gc 0
 | |
| 		if [ "$random" -a $width -gt 2 ]; then
 | |
| 			test_line $gc $((RANDOM % ($width - 2) + 1))
 | |
| 		fi
 | |
| 		test_line $gc $(($width - 1))
 | |
| 		test_no_line $gc $width
 | |
| 	done
 | |
| 	[ "${1:-}" ] && fail "missing expected chip of width $1"
 | |
| 	remove_module || fail "failed to remove module with error $?"
 | |
| }
 | |
| 
 | |
| while getopts ":frvt:" opt; do
 | |
| 	case $opt in
 | |
| 	f)
 | |
| 		full_test=true
 | |
| 		;;
 | |
| 	r)
 | |
| 		random=true
 | |
| 		;;
 | |
| 	t)
 | |
| 		dev_type=$OPTARG
 | |
| 		;;
 | |
| 	v)
 | |
| 		verbose=true
 | |
| 		;;
 | |
| 	*)
 | |
| 		usage
 | |
| 		;;
 | |
| 	esac
 | |
| done
 | |
| shift $((OPTIND - 1))
 | |
| 
 | |
| [ "${1:-}" ] && fail "unknown argument '$1'"
 | |
| 
 | |
| prerequisite
 | |
| 
 | |
| trap 'exit $ksft_fail' SIGTERM SIGINT
 | |
| trap cleanup EXIT
 | |
| 
 | |
| case "$dev_type" in
 | |
| sysfs)
 | |
| 	source $BASE/gpio-mockup-sysfs.sh
 | |
| 	echo "WARNING: gpio sysfs ABI is deprecated."
 | |
| 	;;
 | |
| cdev_v1)
 | |
| 	echo "WARNING: gpio cdev ABI v1 is deprecated."
 | |
| 	uapi_opt="-u1 "
 | |
| 	;;
 | |
| cdev)
 | |
| 	;;
 | |
| *)
 | |
| 	fail "unknown interface type: $dev_type"
 | |
| 	;;
 | |
| esac
 | |
| 
 | |
| remove_module || fail "can't remove existing $module module"
 | |
| 
 | |
| # manual gpio allocation tests fail if a physical chip already exists
 | |
| [ "$full_test" -a -e "/dev/gpiochip0" ] && skip "full tests conflict with gpiochip0"
 | |
| 
 | |
| echo "1.  Module load tests"
 | |
| echo "1.1.  dynamic allocation of gpio"
 | |
| insmod_test "-1,32" 32
 | |
| insmod_test "-1,23,-1,32" 23 32
 | |
| insmod_test "-1,23,-1,26,-1,32" 23 26 32
 | |
| if [ "$full_test" ]; then
 | |
| 	echo "1.2.  manual allocation of gpio"
 | |
| 	insmod_test "0,32" 32
 | |
| 	insmod_test "0,32,32,60" 32 28
 | |
| 	insmod_test "0,32,40,64,64,96" 32 24 32
 | |
| 	echo "1.3.  dynamic and manual allocation of gpio"
 | |
| 	insmod_test "-1,32,32,62" 32 30
 | |
| 	insmod_test "-1,22,-1,23,0,24,32,64" 22 23 24 32
 | |
| 	insmod_test "-1,32,32,60,-1,29" 32 28 29
 | |
| 	insmod_test "-1,32,40,64,-1,5" 32 24 5
 | |
| 	insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31
 | |
| fi
 | |
| echo "2.  Module load error tests"
 | |
| echo "2.1 gpio overflow"
 | |
| # Currently: The max number of gpio(1024) is defined in arm architecture.
 | |
| insmod_test "-1,1024"
 | |
| if [ "$full_test" ]; then
 | |
| 	echo "2.2 no lines defined"
 | |
| 	insmod_test "0,0"
 | |
| 	echo "2.3 ignore range overlap"
 | |
| 	insmod_test "0,32,0,1" 32
 | |
| 	insmod_test "0,32,1,5" 32
 | |
| 	insmod_test "0,32,30,35" 32
 | |
| 	insmod_test "0,32,31,32" 32
 | |
| 	insmod_test "10,32,30,35" 22
 | |
| 	insmod_test "10,32,9,14" 22
 | |
| 	insmod_test "0,32,20,21,40,56" 32 16
 | |
| 	insmod_test "0,32,32,64,32,40" 32 32
 | |
| 	insmod_test "0,32,32,64,36,37" 32 32
 | |
| 	insmod_test "0,32,35,64,34,36" 32 29
 | |
| 	insmod_test "0,30,35,64,35,45" 30 29
 | |
| 	insmod_test "0,32,40,56,30,33" 32 16
 | |
| 	insmod_test "0,32,40,56,30,41" 32 16
 | |
| 	insmod_test "0,32,40,56,39,45" 32 16
 | |
| fi
 | |
| 
 | |
| echo "GPIO $module test PASS"
 |