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