xref: /illumos-gate/usr/src/test/os-tests/tests/gpio/gpio_lookup.c (revision fd71220ba0fafcc9cf5ea0785db206f3f31336e7)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2023 Oxide Computer Company
14  */
15 
16 /*
17  * This test verifies that we can look up names across the gpio_sim controllers
18  * and that all three return the same results for a given pin.
19  */
20 
21 #include <err.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <sys/sysmacros.h>
27 #include <stdbool.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31 
32 #include <sys/gpio/kgpio.h>
33 
34 static int gpio_lookup_ret = EXIT_SUCCESS;
35 static const char *gpio_paths[] = {
36 	"/devices/pseudo/kgpio@0:gpio_sim0",
37 	"/devices/pseudo/kgpio@0:gpio_sim1",
38 	"/devices/pseudo/kgpio@0:gpio_sim2"
39 };
40 
41 static const char *gpio_names[] = {
42 	"3v3",
43 	"periodic-500ms",
44 	"open-drain"
45 };
46 
47 static void
gpio_lookup(int fd,const char * name,uint32_t * idp)48 gpio_lookup(int fd, const char *name, uint32_t *idp)
49 {
50 	kgpio_ioc_name2id_t kin;
51 
52 	(void) memset(&kin, 0, sizeof (kin));
53 	if (strlcpy(kin.kin_name, name, sizeof (kin.kin_name)) >=
54 	    sizeof (kin.kin_name)) {
55 		errx(EXIT_FAILURE, "would have exceeded kin_name with %s",
56 		    name);
57 	}
58 
59 	if (ioctl(fd, KGPIO_IOC_GPIO_NAME2ID, &kin) != 0) {
60 		warn("TEST FAILED: failed to translate %s", name);
61 		gpio_lookup_ret = EXIT_FAILURE;
62 	} else {
63 		*idp = kin.kin_id;
64 	}
65 }
66 
67 /*
68  * Generate a few different error cases that we know to expect:
69  *
70  *  o Invalid name due to no '\0'
71  *  o Invalid name of length 0
72  *  o An unkonwn name
73  */
74 static void
gpio_lookup_errs(int fd)75 gpio_lookup_errs(int fd)
76 {
77 	kgpio_ioc_name2id_t kin;
78 
79 	(void) memset(&kin, 0, sizeof (kin));
80 	if (ioctl(fd, KGPIO_IOC_GPIO_NAME2ID, &kin) == 0) {
81 		warnx("TEST FAILED: zero length lookup passed, expected "
82 		    "EINVAL");
83 		gpio_lookup_ret = EXIT_FAILURE;
84 	} else if (errno != EINVAL) {
85 		warn("TEST FAILED: zero length lookup had wrong errno, "
86 		    "expected EINVAL, found");
87 		gpio_lookup_ret = EXIT_FAILURE;
88 	}
89 
90 	(void) memset(kin.kin_name, 'a', sizeof (kin.kin_name));
91 	if (ioctl(fd, KGPIO_IOC_GPIO_NAME2ID, &kin) == 0) {
92 		warnx("TEST FAILED: no '\\0' lookup passed, expected "
93 		    "EINVAL");
94 		gpio_lookup_ret = EXIT_FAILURE;
95 	} else if (errno != EINVAL) {
96 		warn("TEST FAILED: no '\\0' lookup had wrong errno, "
97 		    "expected EINVAL, found");
98 		gpio_lookup_ret = EXIT_FAILURE;
99 	}
100 
101 	(void) strlcpy(kin.kin_name, "three rings for elven kings",
102 	    sizeof (kin.kin_name));
103 	if (ioctl(fd, KGPIO_IOC_GPIO_NAME2ID, &kin) == 0) {
104 		warnx("TEST FAILED: found rings for elven kings, expected "
105 		    "ENOENT");
106 		gpio_lookup_ret = EXIT_FAILURE;
107 	} else if (errno != ENOENT) {
108 		warn("TEST FAILED: rings for elven kings had wrong errno, "
109 		    "expected ENOENT, found");
110 		gpio_lookup_ret = EXIT_FAILURE;
111 	}
112 }
113 
114 int
main(void)115 main(void)
116 {
117 	int fds[ARRAY_SIZE(gpio_paths)];
118 	uint32_t found_ids[ARRAY_SIZE(gpio_paths)];
119 
120 	for (size_t i = 0; i < ARRAY_SIZE(gpio_paths); i++) {
121 		fds[i] = open(gpio_paths[i], O_RDONLY);
122 		if (fds[i] < 0) {
123 			err(EXIT_FAILURE, "failed to open controller %s",
124 			    gpio_paths[i]);
125 		}
126 	}
127 
128 	/*
129 	 * We expect all of these to be successful.
130 	 */
131 	for (size_t name = 0; name < ARRAY_SIZE(gpio_names); name++) {
132 		uint32_t id0;
133 
134 		for (size_t ctrl = 0; ctrl < ARRAY_SIZE(gpio_paths); ctrl++) {
135 			gpio_lookup(fds[ctrl], gpio_names[name],
136 			    &found_ids[ctrl]);
137 		}
138 
139 		id0 = found_ids[0];
140 		for (size_t ctrl = 0; ctrl < ARRAY_SIZE(gpio_paths); ctrl++) {
141 			if (found_ids[ctrl] != id0) {
142 				warnx("ID Mismatch for %s: got %u on "
143 				    "%s and %u on %s", gpio_names[name],
144 				    id0, gpio_paths[0], found_ids[ctrl],
145 				    gpio_paths[ctrl]);
146 				gpio_lookup_ret = EXIT_FAILURE;
147 			}
148 		}
149 
150 	}
151 
152 	gpio_lookup_errs(fds[0]);
153 
154 	return (gpio_lookup_ret);
155 }
156