xref: /illumos-gate/usr/src/test/os-tests/tests/gpio/gpio_attr.c (revision fd71220ba0fafcc9cf5ea0785db206f3f31336e7)
1*fd71220bSRobert Mustacchi /*
2*fd71220bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*fd71220bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*fd71220bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*fd71220bSRobert Mustacchi  * 1.0 of the CDDL.
6*fd71220bSRobert Mustacchi  *
7*fd71220bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*fd71220bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*fd71220bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*fd71220bSRobert Mustacchi  */
11*fd71220bSRobert Mustacchi 
12*fd71220bSRobert Mustacchi /*
13*fd71220bSRobert Mustacchi  * Copyright 2022 Oxide Computer Company
14*fd71220bSRobert Mustacchi  */
15*fd71220bSRobert Mustacchi 
16*fd71220bSRobert Mustacchi /*
17*fd71220bSRobert Mustacchi  * This test focuses on trying to manipulate GPIO attributes at the kernel ioctl
18*fd71220bSRobert Mustacchi  * level and verifying that the various failure modes we expect are generated.
19*fd71220bSRobert Mustacchi  * We opt not to use libxpio here because libxpio purposefully does not support
20*fd71220bSRobert Mustacchi  * generating various error cases.
21*fd71220bSRobert Mustacchi  *
22*fd71220bSRobert Mustacchi  * This test always operates against the gpio_sim2 controller.
23*fd71220bSRobert Mustacchi  */
24*fd71220bSRobert Mustacchi 
25*fd71220bSRobert Mustacchi #include <err.h>
26*fd71220bSRobert Mustacchi #include <sys/stat.h>
27*fd71220bSRobert Mustacchi #include <sys/types.h>
28*fd71220bSRobert Mustacchi #include <fcntl.h>
29*fd71220bSRobert Mustacchi #include <stdlib.h>
30*fd71220bSRobert Mustacchi #include <unistd.h>
31*fd71220bSRobert Mustacchi #include <libnvpair.h>
32*fd71220bSRobert Mustacchi #include <stdbool.h>
33*fd71220bSRobert Mustacchi #include <string.h>
34*fd71220bSRobert Mustacchi #include <sys/sysmacros.h>
35*fd71220bSRobert Mustacchi #include <errno.h>
36*fd71220bSRobert Mustacchi #include <sys/debug.h>
37*fd71220bSRobert Mustacchi 
38*fd71220bSRobert Mustacchi #include <sys/gpio/kgpio.h>
39*fd71220bSRobert Mustacchi #include <sys/gpio/gpio_sim.h>
40*fd71220bSRobert Mustacchi 
41*fd71220bSRobert Mustacchi /*
42*fd71220bSRobert Mustacchi  * For now we hardcode the path to our controller rather than discovering it
43*fd71220bSRobert Mustacchi  * through libdevinfo or libxpio.
44*fd71220bSRobert Mustacchi  */
45*fd71220bSRobert Mustacchi static const char *gpio_ctrl_path = "/devices/pseudo/kgpio@0:gpio_sim2";
46*fd71220bSRobert Mustacchi static int gpio_attr_fail = EXIT_SUCCESS;
47*fd71220bSRobert Mustacchi 
48*fd71220bSRobert Mustacchi typedef struct {
49*fd71220bSRobert Mustacchi 	/*
50*fd71220bSRobert Mustacchi 	 * Should the update succeed or fail.
51*fd71220bSRobert Mustacchi 	 */
52*fd71220bSRobert Mustacchi 	bool gat_pass;
53*fd71220bSRobert Mustacchi 	/*
54*fd71220bSRobert Mustacchi 	 * Description of the test case for humans.
55*fd71220bSRobert Mustacchi 	 */
56*fd71220bSRobert Mustacchi 	const char *gat_desc;
57*fd71220bSRobert Mustacchi 	/*
58*fd71220bSRobert Mustacchi 	 * GPIO to actually perform the update on.
59*fd71220bSRobert Mustacchi 	 */
60*fd71220bSRobert Mustacchi 	uint32_t gat_pin;
61*fd71220bSRobert Mustacchi 	/*
62*fd71220bSRobert Mustacchi 	 * Function to create the update nvlist.
63*fd71220bSRobert Mustacchi 	 */
64*fd71220bSRobert Mustacchi 	nvlist_t *(*gat_create)(void);
65*fd71220bSRobert Mustacchi 	/*
66*fd71220bSRobert Mustacchi 	 * Function to check the error nvlist. Not required if gat_pass is true.
67*fd71220bSRobert Mustacchi 	 */
68*fd71220bSRobert Mustacchi 	bool	(*gat_check)(nvlist_t *);
69*fd71220bSRobert Mustacchi } gpio_attr_test_t;
70*fd71220bSRobert Mustacchi 
71*fd71220bSRobert Mustacchi static uint32_t
gpio_nvpair_count(nvlist_t * nvl)72*fd71220bSRobert Mustacchi gpio_nvpair_count(nvlist_t *nvl)
73*fd71220bSRobert Mustacchi {
74*fd71220bSRobert Mustacchi 	uint32_t ret = 0;
75*fd71220bSRobert Mustacchi 
76*fd71220bSRobert Mustacchi 	for (nvpair_t *head = nvlist_next_nvpair(nvl, NULL); head != NULL;
77*fd71220bSRobert Mustacchi 	    head = nvlist_next_nvpair(nvl, head)) {
78*fd71220bSRobert Mustacchi 		ret++;
79*fd71220bSRobert Mustacchi 	}
80*fd71220bSRobert Mustacchi 
81*fd71220bSRobert Mustacchi 	return (ret);
82*fd71220bSRobert Mustacchi }
83*fd71220bSRobert Mustacchi 
84*fd71220bSRobert Mustacchi static bool
gpio_err_key(nvlist_t * nvl,const char * key,kgpio_attr_err_t err)85*fd71220bSRobert Mustacchi gpio_err_key(nvlist_t *nvl, const char *key, kgpio_attr_err_t err)
86*fd71220bSRobert Mustacchi {
87*fd71220bSRobert Mustacchi 	int ret;
88*fd71220bSRobert Mustacchi 	uint32_t val;
89*fd71220bSRobert Mustacchi 
90*fd71220bSRobert Mustacchi 	if ((ret = nvlist_lookup_uint32(nvl, key, &val)) != 0) {
91*fd71220bSRobert Mustacchi 		warnx("failed to lookup %s: %s", key, strerror(ret));
92*fd71220bSRobert Mustacchi 		return (false);
93*fd71220bSRobert Mustacchi 	}
94*fd71220bSRobert Mustacchi 
95*fd71220bSRobert Mustacchi 	if (val != err) {
96*fd71220bSRobert Mustacchi 		warnx("error for %s is wrong: found 0x%x, expected 0x%x",
97*fd71220bSRobert Mustacchi 		    key, val, err);
98*fd71220bSRobert Mustacchi 		return (false);
99*fd71220bSRobert Mustacchi 	}
100*fd71220bSRobert Mustacchi 
101*fd71220bSRobert Mustacchi 	return (true);
102*fd71220bSRobert Mustacchi }
103*fd71220bSRobert Mustacchi 
104*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkrdonly(void)105*fd71220bSRobert Mustacchi gpio_mkrdonly(void)
106*fd71220bSRobert Mustacchi {
107*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
108*fd71220bSRobert Mustacchi 
109*fd71220bSRobert Mustacchi 	fnvlist_add_string(nvl, KGPIO_ATTR_NAME, "foobar");
110*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_INPUT, GPIO_SIM_INPUT_LOW);
111*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_VOLTAGE, GPIO_SIM_VOLTAGE_54P5);
112*fd71220bSRobert Mustacchi 	return (nvl);
113*fd71220bSRobert Mustacchi }
114*fd71220bSRobert Mustacchi 
115*fd71220bSRobert Mustacchi static bool
gpio_chkrdonly(nvlist_t * nvl)116*fd71220bSRobert Mustacchi gpio_chkrdonly(nvlist_t *nvl)
117*fd71220bSRobert Mustacchi {
118*fd71220bSRobert Mustacchi 	uint32_t count;
119*fd71220bSRobert Mustacchi 	bool ret = true;
120*fd71220bSRobert Mustacchi 
121*fd71220bSRobert Mustacchi 	count = gpio_nvpair_count(nvl);
122*fd71220bSRobert Mustacchi 	if (count != 3) {
123*fd71220bSRobert Mustacchi 		warnx("encountered incorrect number of keys: %u, expected %u",
124*fd71220bSRobert Mustacchi 		    count, 3);
125*fd71220bSRobert Mustacchi 		ret = false;
126*fd71220bSRobert Mustacchi 	}
127*fd71220bSRobert Mustacchi 
128*fd71220bSRobert Mustacchi 	if (!gpio_err_key(nvl, KGPIO_ATTR_NAME, KGPIO_ATTR_ERR_ATTR_RO) ||
129*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_INPUT, KGPIO_ATTR_ERR_ATTR_RO) ||
130*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_VOLTAGE, KGPIO_ATTR_ERR_ATTR_RO)) {
131*fd71220bSRobert Mustacchi 		ret = false;
132*fd71220bSRobert Mustacchi 	}
133*fd71220bSRobert Mustacchi 
134*fd71220bSRobert Mustacchi 	return (ret);
135*fd71220bSRobert Mustacchi }
136*fd71220bSRobert Mustacchi 
137*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkunknown(void)138*fd71220bSRobert Mustacchi gpio_mkunknown(void)
139*fd71220bSRobert Mustacchi {
140*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
141*fd71220bSRobert Mustacchi 
142*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, "calvinball", 0x23);
143*fd71220bSRobert Mustacchi 	return (nvl);
144*fd71220bSRobert Mustacchi }
145*fd71220bSRobert Mustacchi 
146*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkunknown_valid(void)147*fd71220bSRobert Mustacchi gpio_mkunknown_valid(void)
148*fd71220bSRobert Mustacchi {
149*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
150*fd71220bSRobert Mustacchi 
151*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, "calvinball", 0x23);
152*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_SPEED, GPIO_SIM_SPEED_MEDIUM);
153*fd71220bSRobert Mustacchi 	return (nvl);
154*fd71220bSRobert Mustacchi }
155*fd71220bSRobert Mustacchi 
156*fd71220bSRobert Mustacchi static bool
gpio_chkunknown(nvlist_t * nvl)157*fd71220bSRobert Mustacchi gpio_chkunknown(nvlist_t *nvl)
158*fd71220bSRobert Mustacchi {
159*fd71220bSRobert Mustacchi 	uint32_t count;
160*fd71220bSRobert Mustacchi 	bool ret = true;
161*fd71220bSRobert Mustacchi 
162*fd71220bSRobert Mustacchi 	count = gpio_nvpair_count(nvl);
163*fd71220bSRobert Mustacchi 	if (count != 1) {
164*fd71220bSRobert Mustacchi 		warnx("encountered incorrect number of keys: %u, expected %u",
165*fd71220bSRobert Mustacchi 		    count, 1);
166*fd71220bSRobert Mustacchi 		ret = false;
167*fd71220bSRobert Mustacchi 	}
168*fd71220bSRobert Mustacchi 
169*fd71220bSRobert Mustacchi 	if (!gpio_err_key(nvl, "calvinball", KGPIO_ATTR_ERR_UNKNOWN_ATTR)) {
170*fd71220bSRobert Mustacchi 		ret = false;
171*fd71220bSRobert Mustacchi 	}
172*fd71220bSRobert Mustacchi 
173*fd71220bSRobert Mustacchi 	return (ret);
174*fd71220bSRobert Mustacchi }
175*fd71220bSRobert Mustacchi 
176*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkbadtype_string(void)177*fd71220bSRobert Mustacchi gpio_mkbadtype_string(void)
178*fd71220bSRobert Mustacchi {
179*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
180*fd71220bSRobert Mustacchi 
181*fd71220bSRobert Mustacchi 	fnvlist_add_string(nvl, GPIO_SIM_ATTR_PULL, "link!");
182*fd71220bSRobert Mustacchi 	fnvlist_add_string(nvl, GPIO_SIM_ATTR_OUTPUT, "zelda!");
183*fd71220bSRobert Mustacchi 	return (nvl);
184*fd71220bSRobert Mustacchi }
185*fd71220bSRobert Mustacchi 
186*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkbadtype_nvl(void)187*fd71220bSRobert Mustacchi gpio_mkbadtype_nvl(void)
188*fd71220bSRobert Mustacchi {
189*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
190*fd71220bSRobert Mustacchi 	nvlist_t *nested = fnvlist_alloc();
191*fd71220bSRobert Mustacchi 
192*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nested, GPIO_SIM_ATTR_PULL, 1);
193*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nested, GPIO_SIM_ATTR_OUTPUT, 2);
194*fd71220bSRobert Mustacchi 	fnvlist_add_nvlist(nvl, GPIO_SIM_ATTR_PULL, nested);
195*fd71220bSRobert Mustacchi 	fnvlist_add_nvlist(nvl, GPIO_SIM_ATTR_OUTPUT, nested);
196*fd71220bSRobert Mustacchi 	nvlist_free(nested);
197*fd71220bSRobert Mustacchi 
198*fd71220bSRobert Mustacchi 	return (nvl);
199*fd71220bSRobert Mustacchi }
200*fd71220bSRobert Mustacchi 
201*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkbadtype_array(void)202*fd71220bSRobert Mustacchi gpio_mkbadtype_array(void)
203*fd71220bSRobert Mustacchi {
204*fd71220bSRobert Mustacchi 	uint32_t vals[] = { 0x23, 0x42, 0x169 };
205*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
206*fd71220bSRobert Mustacchi 
207*fd71220bSRobert Mustacchi 	fnvlist_add_uint32_array(nvl, GPIO_SIM_ATTR_PULL, vals,
208*fd71220bSRobert Mustacchi 	    ARRAY_SIZE(vals));
209*fd71220bSRobert Mustacchi 	fnvlist_add_uint32_array(nvl, GPIO_SIM_ATTR_OUTPUT, vals,
210*fd71220bSRobert Mustacchi 	    ARRAY_SIZE(vals));
211*fd71220bSRobert Mustacchi 	return (nvl);
212*fd71220bSRobert Mustacchi }
213*fd71220bSRobert Mustacchi 
214*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkbadtype_s8(void)215*fd71220bSRobert Mustacchi gpio_mkbadtype_s8(void)
216*fd71220bSRobert Mustacchi {
217*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
218*fd71220bSRobert Mustacchi 
219*fd71220bSRobert Mustacchi 	fnvlist_add_int8(nvl, GPIO_SIM_ATTR_PULL, 2);
220*fd71220bSRobert Mustacchi 	fnvlist_add_int8(nvl, GPIO_SIM_ATTR_OUTPUT, 1);
221*fd71220bSRobert Mustacchi 	return (nvl);
222*fd71220bSRobert Mustacchi }
223*fd71220bSRobert Mustacchi 
224*fd71220bSRobert Mustacchi static bool
gpio_chkbadattr(nvlist_t * nvl)225*fd71220bSRobert Mustacchi gpio_chkbadattr(nvlist_t *nvl)
226*fd71220bSRobert Mustacchi {
227*fd71220bSRobert Mustacchi 	uint32_t count;
228*fd71220bSRobert Mustacchi 	bool ret = true;
229*fd71220bSRobert Mustacchi 
230*fd71220bSRobert Mustacchi 	count = gpio_nvpair_count(nvl);
231*fd71220bSRobert Mustacchi 	if (count != 2) {
232*fd71220bSRobert Mustacchi 		warnx("encountered incorrect number of keys: %u, expected %u",
233*fd71220bSRobert Mustacchi 		    count, 2);
234*fd71220bSRobert Mustacchi 		ret = false;
235*fd71220bSRobert Mustacchi 	}
236*fd71220bSRobert Mustacchi 
237*fd71220bSRobert Mustacchi 	if (!gpio_err_key(nvl, GPIO_SIM_ATTR_PULL, KGPIO_ATTR_ERR_BAD_TYPE) ||
238*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_OUTPUT, KGPIO_ATTR_ERR_BAD_TYPE)) {
239*fd71220bSRobert Mustacchi 		ret = false;
240*fd71220bSRobert Mustacchi 	}
241*fd71220bSRobert Mustacchi 
242*fd71220bSRobert Mustacchi 	return (ret);
243*fd71220bSRobert Mustacchi }
244*fd71220bSRobert Mustacchi 
245*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkbadval(void)246*fd71220bSRobert Mustacchi gpio_mkbadval(void)
247*fd71220bSRobert Mustacchi {
248*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
249*fd71220bSRobert Mustacchi 
250*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_OUTPUT, 0x42);
251*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_PULL, UINT32_MAX);
252*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_SPEED,
253*fd71220bSRobert Mustacchi 	    GPIO_SIM_SPEED_VERY_HIGH * 10);
254*fd71220bSRobert Mustacchi 	return (nvl);
255*fd71220bSRobert Mustacchi }
256*fd71220bSRobert Mustacchi 
257*fd71220bSRobert Mustacchi static bool
gpio_chkbadval(nvlist_t * nvl)258*fd71220bSRobert Mustacchi gpio_chkbadval(nvlist_t *nvl)
259*fd71220bSRobert Mustacchi {
260*fd71220bSRobert Mustacchi 	uint32_t count;
261*fd71220bSRobert Mustacchi 	bool ret = true;
262*fd71220bSRobert Mustacchi 
263*fd71220bSRobert Mustacchi 	count = gpio_nvpair_count(nvl);
264*fd71220bSRobert Mustacchi 	if (count != 3) {
265*fd71220bSRobert Mustacchi 		warnx("encountered incorrect number of keys: %u, expected %u",
266*fd71220bSRobert Mustacchi 		    count, 3);
267*fd71220bSRobert Mustacchi 		ret = false;
268*fd71220bSRobert Mustacchi 	}
269*fd71220bSRobert Mustacchi 
270*fd71220bSRobert Mustacchi 	if (!gpio_err_key(nvl, GPIO_SIM_ATTR_PULL,
271*fd71220bSRobert Mustacchi 	    KGPIO_ATTR_ERR_UNKNOWN_VAL) ||
272*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_OUTPUT,
273*fd71220bSRobert Mustacchi 	    KGPIO_ATTR_ERR_UNKNOWN_VAL) ||
274*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_SPEED,
275*fd71220bSRobert Mustacchi 	    KGPIO_ATTR_ERR_UNKNOWN_VAL)) {
276*fd71220bSRobert Mustacchi 		ret = false;
277*fd71220bSRobert Mustacchi 	}
278*fd71220bSRobert Mustacchi 
279*fd71220bSRobert Mustacchi 	return (ret);
280*fd71220bSRobert Mustacchi }
281*fd71220bSRobert Mustacchi 
282*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkcantapply(void)283*fd71220bSRobert Mustacchi gpio_mkcantapply(void)
284*fd71220bSRobert Mustacchi {
285*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
286*fd71220bSRobert Mustacchi 
287*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_OUTPUT, GPIO_SIM_OUTPUT_HIGH);
288*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_PULL, GPIO_SIM_PULL_UP_5K);
289*fd71220bSRobert Mustacchi 	return (nvl);
290*fd71220bSRobert Mustacchi }
291*fd71220bSRobert Mustacchi 
292*fd71220bSRobert Mustacchi static bool
gpio_chkcantapply(nvlist_t * nvl)293*fd71220bSRobert Mustacchi gpio_chkcantapply(nvlist_t *nvl)
294*fd71220bSRobert Mustacchi {
295*fd71220bSRobert Mustacchi 	uint32_t count;
296*fd71220bSRobert Mustacchi 	bool ret = true;
297*fd71220bSRobert Mustacchi 
298*fd71220bSRobert Mustacchi 	count = gpio_nvpair_count(nvl);
299*fd71220bSRobert Mustacchi 	if (count != 2) {
300*fd71220bSRobert Mustacchi 		warnx("encountered incorrect number of keys: %u, expected %u",
301*fd71220bSRobert Mustacchi 		    count, 2);
302*fd71220bSRobert Mustacchi 		ret = false;
303*fd71220bSRobert Mustacchi 	}
304*fd71220bSRobert Mustacchi 
305*fd71220bSRobert Mustacchi 	if (!gpio_err_key(nvl, GPIO_SIM_ATTR_PULL,
306*fd71220bSRobert Mustacchi 	    KGPIO_ATTR_ERR_CANT_APPLY_VAL) ||
307*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_OUTPUT,
308*fd71220bSRobert Mustacchi 	    KGPIO_ATTR_ERR_CANT_APPLY_VAL)) {
309*fd71220bSRobert Mustacchi 		ret = false;
310*fd71220bSRobert Mustacchi 	}
311*fd71220bSRobert Mustacchi 
312*fd71220bSRobert Mustacchi 	return (ret);
313*fd71220bSRobert Mustacchi }
314*fd71220bSRobert Mustacchi 
315*fd71220bSRobert Mustacchi static nvlist_t *
gpio_mkmulti(void)316*fd71220bSRobert Mustacchi gpio_mkmulti(void)
317*fd71220bSRobert Mustacchi {
318*fd71220bSRobert Mustacchi 	nvlist_t *nvl = fnvlist_alloc();
319*fd71220bSRobert Mustacchi 
320*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_OUTPUT, GPIO_SIM_OUTPUT_HIGH);
321*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_VOLTAGE, GPIO_SIM_VOLTAGE_54P5);
322*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, "triforce", 0x23);
323*fd71220bSRobert Mustacchi 	fnvlist_add_string(nvl, GPIO_SIM_ATTR_PULL, "magecite");
324*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, GPIO_SIM_ATTR_SPEED, 0xbadcafe);
325*fd71220bSRobert Mustacchi 
326*fd71220bSRobert Mustacchi 	return (nvl);
327*fd71220bSRobert Mustacchi }
328*fd71220bSRobert Mustacchi 
329*fd71220bSRobert Mustacchi static bool
gpio_chkmulti(nvlist_t * nvl)330*fd71220bSRobert Mustacchi gpio_chkmulti(nvlist_t *nvl)
331*fd71220bSRobert Mustacchi {
332*fd71220bSRobert Mustacchi 	uint32_t count;
333*fd71220bSRobert Mustacchi 	bool ret = true;
334*fd71220bSRobert Mustacchi 
335*fd71220bSRobert Mustacchi 	count = gpio_nvpair_count(nvl);
336*fd71220bSRobert Mustacchi 	if (count != 5) {
337*fd71220bSRobert Mustacchi 		warnx("encountered incorrect number of keys: %u, expected %u",
338*fd71220bSRobert Mustacchi 		    count, 5);
339*fd71220bSRobert Mustacchi 		ret = false;
340*fd71220bSRobert Mustacchi 	}
341*fd71220bSRobert Mustacchi 
342*fd71220bSRobert Mustacchi 	if (!gpio_err_key(nvl, GPIO_SIM_ATTR_VOLTAGE, KGPIO_ATTR_ERR_ATTR_RO) ||
343*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_OUTPUT,
344*fd71220bSRobert Mustacchi 	    KGPIO_ATTR_ERR_CANT_APPLY_VAL) ||
345*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, "triforce", KGPIO_ATTR_ERR_UNKNOWN_ATTR) ||
346*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_PULL, KGPIO_ATTR_ERR_BAD_TYPE) ||
347*fd71220bSRobert Mustacchi 	    !gpio_err_key(nvl, GPIO_SIM_ATTR_SPEED,
348*fd71220bSRobert Mustacchi 	    KGPIO_ATTR_ERR_UNKNOWN_VAL)) {
349*fd71220bSRobert Mustacchi 		ret = false;
350*fd71220bSRobert Mustacchi 	}
351*fd71220bSRobert Mustacchi 
352*fd71220bSRobert Mustacchi 	return (ret);
353*fd71220bSRobert Mustacchi }
354*fd71220bSRobert Mustacchi 
355*fd71220bSRobert Mustacchi static const gpio_attr_test_t gpio_attr_tests[] = {
356*fd71220bSRobert Mustacchi 	{ false, "update read-only value fails", 2, gpio_mkrdonly,
357*fd71220bSRobert Mustacchi 	    gpio_chkrdonly },
358*fd71220bSRobert Mustacchi 	{ false, "unknown attribute fails", 2, gpio_mkunknown,
359*fd71220bSRobert Mustacchi 	    gpio_chkunknown },
360*fd71220bSRobert Mustacchi 	{ false, "unknown/valid attribute fails", 2, gpio_mkunknown_valid,
361*fd71220bSRobert Mustacchi 	    gpio_chkunknown },
362*fd71220bSRobert Mustacchi 	{ false, "bad attribute type 0 (string)", 0, gpio_mkbadtype_string,
363*fd71220bSRobert Mustacchi 	    gpio_chkbadattr },
364*fd71220bSRobert Mustacchi 	{ false, "bad attribute type 1 (nvlist)", 0, gpio_mkbadtype_nvl,
365*fd71220bSRobert Mustacchi 	    gpio_chkbadattr },
366*fd71220bSRobert Mustacchi 	{ false, "bad attribute type 2 (uint32 array)", 0, gpio_mkbadtype_array,
367*fd71220bSRobert Mustacchi 	    gpio_chkbadattr },
368*fd71220bSRobert Mustacchi 	{ false, "bad attribute type 3 (int8)", 0, gpio_mkbadtype_s8,
369*fd71220bSRobert Mustacchi 	    gpio_chkbadattr },
370*fd71220bSRobert Mustacchi 	{ false, "bad values", 1, gpio_mkbadval, gpio_chkbadval },
371*fd71220bSRobert Mustacchi 	{ false, "can't apply value", 5, gpio_mkcantapply, gpio_chkcantapply },
372*fd71220bSRobert Mustacchi 	{ false, "disjoint errors", 5, gpio_mkmulti, gpio_chkmulti },
373*fd71220bSRobert Mustacchi };
374*fd71220bSRobert Mustacchi 
375*fd71220bSRobert Mustacchi static void
gpio_attr_run_one(int ctrl_fd,const gpio_attr_test_t * test)376*fd71220bSRobert Mustacchi gpio_attr_run_one(int ctrl_fd, const gpio_attr_test_t *test)
377*fd71220bSRobert Mustacchi {
378*fd71220bSRobert Mustacchi 	int ret;
379*fd71220bSRobert Mustacchi 	char err_buf[16 * 1024];
380*fd71220bSRobert Mustacchi 	char *buf = NULL;
381*fd71220bSRobert Mustacchi 	size_t buflen = 0;
382*fd71220bSRobert Mustacchi 	kgpio_update_t update;
383*fd71220bSRobert Mustacchi 	nvlist_t *nvl;
384*fd71220bSRobert Mustacchi 
385*fd71220bSRobert Mustacchi 	nvl = test->gat_create();
386*fd71220bSRobert Mustacchi 	if (nvl == NULL) {
387*fd71220bSRobert Mustacchi 		gpio_attr_fail = EXIT_FAILURE;
388*fd71220bSRobert Mustacchi 		(void) fprintf(stderr, "TEST FAILED: %s: failed to make "
389*fd71220bSRobert Mustacchi 		    "nvlist\n", test->gat_desc);
390*fd71220bSRobert Mustacchi 		return;
391*fd71220bSRobert Mustacchi 	}
392*fd71220bSRobert Mustacchi 
393*fd71220bSRobert Mustacchi 	ret = nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0);
394*fd71220bSRobert Mustacchi 	if (ret != 0) {
395*fd71220bSRobert Mustacchi 		gpio_attr_fail = EXIT_FAILURE;
396*fd71220bSRobert Mustacchi 		(void) fprintf(stderr, "TEST FAILED: %s: failed to pack "
397*fd71220bSRobert Mustacchi 		    "nvlist: %s\n", test->gat_desc, strerror(ret));
398*fd71220bSRobert Mustacchi 		nvlist_free(nvl);
399*fd71220bSRobert Mustacchi 		return;
400*fd71220bSRobert Mustacchi 	}
401*fd71220bSRobert Mustacchi 
402*fd71220bSRobert Mustacchi 	nvlist_free(nvl);
403*fd71220bSRobert Mustacchi 
404*fd71220bSRobert Mustacchi 	(void) memset(&update, 0, sizeof (update));
405*fd71220bSRobert Mustacchi 	update.kgu_id = test->gat_pin;
406*fd71220bSRobert Mustacchi 	update.kgu_attr = (uintptr_t)buf;
407*fd71220bSRobert Mustacchi 	update.kgu_attr_len = buflen;
408*fd71220bSRobert Mustacchi 	update.kgu_err = (uintptr_t)err_buf;
409*fd71220bSRobert Mustacchi 	update.kgu_err_len = sizeof (err_buf);
410*fd71220bSRobert Mustacchi 
411*fd71220bSRobert Mustacchi 	if (ioctl(ctrl_fd, KGPIO_IOC_GPIO_UPDATE, &update) != 0) {
412*fd71220bSRobert Mustacchi 		gpio_attr_fail = EXIT_FAILURE;
413*fd71220bSRobert Mustacchi 		(void) fprintf(stderr, "TEST FAILED: %s: update ioctl had a "
414*fd71220bSRobert Mustacchi 		    "hard failure: %s\n", test->gat_desc, strerror(errno));
415*fd71220bSRobert Mustacchi 		free(buf);
416*fd71220bSRobert Mustacchi 		return;
417*fd71220bSRobert Mustacchi 	}
418*fd71220bSRobert Mustacchi 
419*fd71220bSRobert Mustacchi 	free(buf);
420*fd71220bSRobert Mustacchi 	bool pass = (update.kgu_flags & KGPIO_UPDATE_ERROR) == 0;
421*fd71220bSRobert Mustacchi 
422*fd71220bSRobert Mustacchi 	if (test->gat_pass && pass) {
423*fd71220bSRobert Mustacchi 		(void) printf("TEST PASSED: %s\n", test->gat_desc);
424*fd71220bSRobert Mustacchi 	} else if (test->gat_pass && !pass) {
425*fd71220bSRobert Mustacchi 		gpio_attr_fail = EXIT_FAILURE;
426*fd71220bSRobert Mustacchi 		(void) fprintf(stderr, "TEST FAILED: %s: expected update to "
427*fd71220bSRobert Mustacchi 		    "succeed, but failed\n", test->gat_desc);
428*fd71220bSRobert Mustacchi 	} else if (pass) {
429*fd71220bSRobert Mustacchi 		gpio_attr_fail = EXIT_FAILURE;
430*fd71220bSRobert Mustacchi 		(void) fprintf(stderr, "TEST FAILED: %s: expected update to "
431*fd71220bSRobert Mustacchi 		    "fail, but succeeded\n", test->gat_desc);
432*fd71220bSRobert Mustacchi 	} else {
433*fd71220bSRobert Mustacchi 		nvlist_t *err_nvl;
434*fd71220bSRobert Mustacchi 
435*fd71220bSRobert Mustacchi 		if ((update.kgu_flags & KGPIO_UPDATE_ERR_NVL_VALID) == 0) {
436*fd71220bSRobert Mustacchi 			gpio_attr_fail = EXIT_FAILURE;
437*fd71220bSRobert Mustacchi 			(void) fprintf(stderr, "TEST FAILED: %s: kernel failed "
438*fd71220bSRobert Mustacchi 			    "to give us valid error data\n");
439*fd71220bSRobert Mustacchi 			return;
440*fd71220bSRobert Mustacchi 		}
441*fd71220bSRobert Mustacchi 
442*fd71220bSRobert Mustacchi 		ret = nvlist_unpack(err_buf, update.kgu_err_len, &err_nvl, 0);
443*fd71220bSRobert Mustacchi 		if (ret != 0) {
444*fd71220bSRobert Mustacchi 			gpio_attr_fail = EXIT_FAILURE;
445*fd71220bSRobert Mustacchi 			(void) fprintf(stderr, "TEST FAILED: %s: failed to "
446*fd71220bSRobert Mustacchi 			    "unpack error nvlist: %s\n", test->gat_desc,
447*fd71220bSRobert Mustacchi 			    strerror(ret));
448*fd71220bSRobert Mustacchi 			return;
449*fd71220bSRobert Mustacchi 		}
450*fd71220bSRobert Mustacchi 
451*fd71220bSRobert Mustacchi 		if (!test->gat_check(err_nvl)) {
452*fd71220bSRobert Mustacchi 			gpio_attr_fail = EXIT_FAILURE;
453*fd71220bSRobert Mustacchi 			(void) fprintf(stderr, "TEST FAILED: %s: error nvlist "
454*fd71220bSRobert Mustacchi 			    "incorrect\n", test->gat_desc);
455*fd71220bSRobert Mustacchi 		} else {
456*fd71220bSRobert Mustacchi 			(void) printf("TEST PASSED: %s\n", test->gat_desc);
457*fd71220bSRobert Mustacchi 		}
458*fd71220bSRobert Mustacchi 
459*fd71220bSRobert Mustacchi 		nvlist_free(err_nvl);
460*fd71220bSRobert Mustacchi 	}
461*fd71220bSRobert Mustacchi }
462*fd71220bSRobert Mustacchi 
463*fd71220bSRobert Mustacchi int
main(void)464*fd71220bSRobert Mustacchi main(void)
465*fd71220bSRobert Mustacchi {
466*fd71220bSRobert Mustacchi 	int ctrl_fd;
467*fd71220bSRobert Mustacchi 
468*fd71220bSRobert Mustacchi 	ctrl_fd = open(gpio_ctrl_path, O_RDWR);
469*fd71220bSRobert Mustacchi 	if (ctrl_fd < 0) {
470*fd71220bSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open controller %s",
471*fd71220bSRobert Mustacchi 		    gpio_ctrl_path);
472*fd71220bSRobert Mustacchi 	}
473*fd71220bSRobert Mustacchi 
474*fd71220bSRobert Mustacchi 	for (uint32_t i = 0; i < ARRAY_SIZE(gpio_attr_tests); i++) {
475*fd71220bSRobert Mustacchi 		gpio_attr_run_one(ctrl_fd, &gpio_attr_tests[i]);
476*fd71220bSRobert Mustacchi 	}
477*fd71220bSRobert Mustacchi 
478*fd71220bSRobert Mustacchi 	(void) close(ctrl_fd);
479*fd71220bSRobert Mustacchi 
480*fd71220bSRobert Mustacchi 	if (gpio_attr_fail == EXIT_SUCCESS) {
481*fd71220bSRobert Mustacchi 		(void) printf("All tests passed successfully!\n");
482*fd71220bSRobert Mustacchi 	}
483*fd71220bSRobert Mustacchi 	return (gpio_attr_fail);
484*fd71220bSRobert Mustacchi }
485