xref: /illumos-gate/usr/src/lib/libxpio/common/libxpio_attr.c (revision a3ebb524df668b0fc3a38f33d0049380f5f11ec1)
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 2022 Oxide Computer Company
14  */
15 
16 /*
17  * This file implements all of the access to and manipulating of attributes. An
18  * attribute is a thinly veiled reference to the underlying nvlist_t of data
19  * that we were given. Attributes are treated as the underlying nvpair data.
20  * This gets us out of some allocation bits, but means that we need to always
21  * ask for the gpio information itself depending on what we're trying to do as
22  * that has a pointer to our nvlist.
23  */
24 
25 #include <strings.h>
26 #include <sys/gpio/zen_gpio.h>
27 #include <sys/gpio/gpio_sim.h>
28 #include <sys/gpio/pca953x.h>
29 #include <sys/gpio/ltc4306.h>
30 #include <sys/sysmacros.h>
31 
32 #include "libxpio_impl.h"
33 
34 /*
35  * These are data tables that exist for each attribute. They provide a general
36  * means of mapping between a string and a known uint32_t value. Currently we
37  * assume that these strings do not need translation and localization. There
38  * should be one table of values which is then wrapped up inside something else.
39  */
40 typedef struct {
41 	uint32_t xp_val;
42 	const char *xp_name;
43 } xpio_pair_t;
44 
45 static const xpio_pair_t zen_gpio_pad_pairs[] = {
46 	{ ZEN_GPIO_PAD_TYPE_GPIO, "gpio" },
47 	{ ZEN_GPIO_PAD_TYPE_SD, "sd" },
48 	{ ZEN_GPIO_PAD_TYPE_I2C, "i2c" },
49 	{ ZEN_GPIO_PAD_TYPE_I3C, "i3c" },
50 	{ 0x00, NULL }
51 };
52 
53 static const xpio_pair_t zen_gpio_cap_pairs[] = {
54 	{ ZEN_GPIO_C_AGPIO, "AGPIO" },
55 	{ ZEN_GPIO_C_REMOTE, "Remote" },
56 	{ 0x00, NULL }
57 };
58 
59 static const xpio_pair_t zen_gpio_driver_pairs[] = {
60 	{ ZEN_GPIO_DRIVER_UNKNOWN, "unknown" },
61 	{ ZEN_GPIO_DRIVER_PUSH_PULL, "push-pull" },
62 	{ ZEN_GPIO_DRIVER_OPEN_DRAIN, "open-drain" },
63 	{ 0x00, NULL }
64 };
65 
66 static const xpio_pair_t zen_gpio_output_pairs[] = {
67 	{ ZEN_GPIO_OUTPUT_DISABLED, "disabled" },
68 	{ ZEN_GPIO_OUTPUT_LOW, "low" },
69 	{ ZEN_GPIO_OUTPUT_HIGH, "high" },
70 	{ 0x00, NULL }
71 };
72 
73 static const xpio_pair_t zen_gpio_input_pairs[] = {
74 	{ ZEN_GPIO_INPUT_LOW, "low" },
75 	{ ZEN_GPIO_INPUT_HIGH, "high" },
76 	{ 0x00, NULL }
77 };
78 
79 static const xpio_pair_t zen_gpio_voltage_pairs[] = {
80 	{ ZEN_GPIO_V_UNKNOWN, "unknown" },
81 	{ ZEN_GPIO_V_1P1_S3, "1.1V" },
82 	{ ZEN_GPIO_V_1P8_S5, "1.8V" },
83 	{ ZEN_GPIO_V_1P8_S0, "1.8V" },
84 	{ ZEN_GPIO_V_3P3_S5, "3.3V" },
85 	{ ZEN_GPIO_V_3P3_S0, "3.3V" },
86 	{ 0x00, NULL }
87 };
88 
89 static const xpio_pair_t zen_gpio_pull_pairs[] = {
90 	{ ZEN_GPIO_PULL_DISABLED, "disabled" },
91 	{ ZEN_GPIO_PULL_DOWN, "down" },
92 	{ ZEN_GPIO_PULL_UP_4K, "4k-up" },
93 	{ ZEN_GPIO_PULL_UP_8K, "8k-up" },
94 	{ ZEN_GPIO_PULL_UP, "up" },
95 	{ ZEN_GPIO_PULL_DOWN_UP, "up|down" },
96 	{ ZEN_GPIO_PULL_DOWN_UP_4K, "4k-up|down" },
97 	{ ZEN_GPIO_PULL_DOWN_UP_8K, "8k-up|down" },
98 	{ 0x00, NULL }
99 };
100 
101 static const xpio_pair_t zen_gpio_drive_pairs[] = {
102 	{ ZEN_GPIO_DRIVE_UNKNOWN, "unknown" },
103 	{ ZEN_GPIO_DRIVE_40R, "40R" },
104 	{ ZEN_GPIO_DRIVE_60R, "60R" },
105 	{ ZEN_GPIO_DRIVE_80R, "80R" },
106 	{ 0x00, NULL }
107 };
108 
109 static const xpio_pair_t zen_gpio_dbt_mode_pairs[] = {
110 	{ ZEN_GPIO_DEBOUNCE_MODE_NONE, "none" },
111 	{ ZEN_GPIO_DEBOUNCE_MODE_KEEP_LOW, "keep-low-glitch" },
112 	{ ZEN_GPIO_DEBOUNCE_MODE_KEEP_HIGH, "keep-high-glitch" },
113 	{ ZEN_GPIO_DEBOUNCE_MODE_REMOVE, "remove-glitch" },
114 	{ 0x00, NULL }
115 };
116 
117 static const xpio_pair_t zen_gpio_dbt_unit_pairs[] = {
118 	{ ZEN_GPIO_DEBOUNCE_UNIT_2RTC, "61us" },
119 	{ ZEN_GPIO_DEBOUNCE_UNIT_8RTC, "244us" },
120 	{ ZEN_GPIO_DEBOUNCE_UNIT_512RTC, "15.6ms" },
121 	{ ZEN_GPIO_DEBOUNCE_UNIT_2048RTC, "62.5ms" },
122 	{ 0x00, NULL }
123 };
124 
125 static const xpio_pair_t zen_gpio_trigger_mode_pairs[] = {
126 	{ ZEN_GPIO_TRIGGER_UNKNOWN, "unknown" },
127 	{ ZEN_GPIO_TRIGGER_EDGE_HIGH, "edge/high" },
128 	{ ZEN_GPIO_TRIGGER_EDGE_LOW, "edge/low" },
129 	{ ZEN_GPIO_TRIGGER_EDGE_BOTH, "edge/both" },
130 	{ ZEN_GPIO_TRIGGER_LEVEL_HIGH, "level/high" },
131 	{ ZEN_GPIO_TRIGGER_LEVEL_LOW, "level/low" },
132 	{ 0x00, NULL }
133 };
134 
135 static const xpio_pair_t zen_gpio_status_pairs[] = {
136 	{ ZEN_GPIO_STATUS_WAKE, "wake" },
137 	{ ZEN_GPIO_STATUS_INTR, "interrupt" },
138 	{ 0x00, NULL }
139 };
140 
141 static const xpio_pair_t gpio_sim_output_pairs[] = {
142 	{ GPIO_SIM_OUTPUT_DISABLED, "disabled" },
143 	{ GPIO_SIM_OUTPUT_LOW, "low" },
144 	{ GPIO_SIM_OUTPUT_HIGH, "high" },
145 	{ 0x00, NULL }
146 };
147 
148 static const xpio_pair_t gpio_sim_input_pairs[] = {
149 	{ GPIO_SIM_INPUT_LOW, "low" },
150 	{ GPIO_SIM_INPUT_HIGH, "high" },
151 	{ 0x00, NULL }
152 };
153 
154 static const xpio_pair_t gpio_sim_pull_pairs[] = {
155 	{ GPIO_SIM_PULL_DISABLED, "disabled" },
156 	{ GPIO_SIM_PULL_DOWN, "down" },
157 	{ GPIO_SIM_PULL_DOWN_23K, "23k-down" },
158 	{ GPIO_SIM_PULL_UP, "up" },
159 	{ GPIO_SIM_PULL_UP_5K, "5k-up" },
160 	{ GPIO_SIM_PULL_UP_40K, "40k-up" },
161 	{ GPIO_SIM_PULL_BOTH, "up|down" },
162 	{ 0x00, NULL }
163 };
164 
165 static const xpio_pair_t gpio_sim_voltage_pairs[] = {
166 	{ GPIO_SIM_VOLTAGE_1P8, "1.8V" },
167 	{ GPIO_SIM_VOLTAGE_3P3, "3.3V" },
168 	{ GPIO_SIM_VOLTAGE_12P0, "12.0V" },
169 	{ GPIO_SIM_VOLTAGE_54P5, "54.5V" },
170 	{ 0x00, NULL }
171 };
172 
173 static const xpio_pair_t gpio_sim_speed_pairs[] = {
174 	{ GPIO_SIM_SPEED_LOW, "low" },
175 	{ GPIO_SIM_SPEED_MEDIUM, "medium" },
176 	{ GPIO_SIM_SPEED_HIGH, "high" },
177 	{ GPIO_SIM_SPEED_VERY_HIGH, "very-high" },
178 	{ 0x00, NULL }
179 };
180 
181 static const xpio_pair_t pca953x_input_pairs[] = {
182 	{ PCA953X_GPIO_INPUT_LOW, "low" },
183 	{ PCA953X_GPIO_INPUT_HIGH, "high" },
184 	{ 0x00, NULL }
185 };
186 
187 static const xpio_pair_t pca953x_output_pairs[] = {
188 	{ PCA953X_GPIO_OUTPUT_DISABLED, "disabled" },
189 	{ PCA953X_GPIO_OUTPUT_LOW, "low" },
190 	{ PCA953X_GPIO_OUTPUT_HIGH, "high" },
191 	{ 0x00, NULL }
192 };
193 
194 static const xpio_pair_t pca953x_polarity_pairs[] = {
195 	{ PCA953X_GPIO_POLARITY_NORMAL, "normal" },
196 	{ PCA953X_GPIO_POLARITY_INVERTED, "inverted" },
197 	{ 0x00, NULL }
198 };
199 
200 static const xpio_pair_t ltc4306_input_pairs[] = {
201 	{ LTC4306_GPIO_INPUT_LOW, "low" },
202 	{ LTC4306_GPIO_INPUT_HIGH, "high" },
203 	{ 0x00, NULL }
204 };
205 
206 static const xpio_pair_t ltc4306_output_pairs[] = {
207 	{ LTC4306_GPIO_OUTPUT_DISABLED, "disabled" },
208 	{ LTC4306_GPIO_OUTPUT_LOW, "low" },
209 	{ LTC4306_GPIO_OUTPUT_HIGH, "high" },
210 	{ 0x00, NULL }
211 };
212 
213 static const xpio_pair_t ltc4306_output_mode_pairs[] = {
214 	{ LTC4306_GPIO_OUTPUT_MODE_PUSH_PULL, "push-pull" },
215 	{ LTC4306_GPIO_OUTPUT_MODE_OPEN_DRAIN, "open-drain" },
216 	{ 0x00, NULL }
217 };
218 
219 /*
220  * These two different functions are intended for different uses. Basically
221  * today most attributes that providers expose are semantic enums that describe
222  * state. The tostr_f function pointer is intended for when translating from the
223  * provider's notion of it to a humans. The tou32_f is intended for translating
224  * from a human's notion to a providers. The latter translation still works for
225  * properties that are read-only, mainly because it is the provider's job to be
226  * the source of truth for what is read-only or not.
227  */
228 typedef bool (*xpio_xlate_tostr_f)(const uint32_t, const xpio_pair_t *, char *,
229     size_t);
230 typedef bool (*xpio_xlate_tou32_f)(const char *, const xpio_pair_t *,
231     uint32_t *);
232 
233 typedef struct {
234 	const char *xt_name;
235 	const xpio_pair_t *xt_pairs;
236 	xpio_xlate_tostr_f xt_xlate_tostr;
237 	xpio_xlate_tou32_f xt_xlate_tou32;
238 } xpio_translate_t;
239 
240 static bool
xpio_attr_xlate_tostr_direct(const uint32_t val,const xpio_pair_t * pairs,char * buf,size_t buflen)241 xpio_attr_xlate_tostr_direct(const uint32_t val, const xpio_pair_t *pairs,
242     char *buf, size_t buflen)
243 {
244 	for (uint_t i = 0; pairs[i].xp_name != NULL; i++) {
245 		if (val == pairs[i].xp_val) {
246 			return (strlcpy(buf, pairs[i].xp_name, buflen) <
247 			    buflen);
248 		}
249 	}
250 	return (false);
251 }
252 
253 static bool
xpio_attr_xlate_tou32_direct(const char * str,const xpio_pair_t * pairs,uint32_t * outp)254 xpio_attr_xlate_tou32_direct(const char *str, const xpio_pair_t *pairs,
255     uint32_t *outp)
256 {
257 	for (uint_t i = 0; pairs[i].xp_name != NULL; i++) {
258 		if (strcmp(str, pairs[i].xp_name) == 0) {
259 			*outp = pairs[i].xp_val;
260 			return (true);
261 		}
262 	}
263 	return (false);
264 }
265 
266 static bool
xpio_attr_xlate_tostr_bitfield(const uint32_t val,const xpio_pair_t * pairs,char * buf,size_t buflen)267 xpio_attr_xlate_tostr_bitfield(const uint32_t val, const xpio_pair_t *pairs,
268     char *buf, size_t buflen)
269 {
270 	size_t off = 0;
271 	bool first = true;
272 
273 	buf[0] = '\0';
274 	for (uint_t i = 0; pairs[i].xp_name != NULL; i++) {
275 		int ret;
276 
277 		if ((pairs[i].xp_val & val) != pairs[i].xp_val) {
278 			continue;
279 		}
280 
281 		ret = snprintf(buf + off, buflen - off, "%s%s",
282 		    first ? "" : "|", pairs[i].xp_name);
283 		if (ret >= (buflen - off)) {
284 			return (false);
285 		}
286 		off += ret;
287 		first = false;
288 	}
289 
290 	return (true);
291 }
292 
293 /*
294  * We expect a bit field to have a series of strings that are | delineated. This
295  * means that we need to search and only look at the portion of the string that
296  * matches the '|'. This leads to use needing to check two things for a match:
297  *
298  *   o That a strncmp() with the found string length matches.
299  *   o That the total length indicates the end of the pair's string. This must
300  *     be done after the first check as the first check returning zero
301  *     effectively gives us a guarantee on the pair's length and that the next
302  *     byte is valid.
303  */
304 static bool
xpio_attr_xlate_tou32_bitfield(const char * str,const xpio_pair_t * pairs,uint32_t * outp)305 xpio_attr_xlate_tou32_bitfield(const char *str, const xpio_pair_t *pairs,
306     uint32_t *outp)
307 {
308 	*outp = 0;
309 	bool found = false;
310 
311 	while (*str != '\0') {
312 		size_t len;
313 		const char *pipe = strchr(str, '|');
314 		bool match = false;
315 
316 		if (pipe != NULL) {
317 			len = (uintptr_t)pipe - (uintptr_t)str;
318 		} else {
319 			len = strlen(str);
320 		}
321 
322 		for (uint_t i = 0; pairs[i].xp_name != NULL; i++) {
323 			if (strncmp(pairs[i].xp_name, str, len) == 0 &&
324 			    pairs[i].xp_name[len] == '\0') {
325 				found = true;
326 				match = true;
327 				*outp |= pairs[i].xp_val;
328 				match = true;
329 				break;
330 			}
331 		}
332 
333 		if (!match) {
334 			return (false);
335 		}
336 
337 		if (pipe != NULL) {
338 			str = pipe + 1;
339 		} else {
340 			break;
341 		}
342 	}
343 
344 	return (found);
345 }
346 
347 static bool
xpio_attr_xlate_tostr_hex(const uint32_t val,const xpio_pair_t * pairs,char * buf,size_t buflen)348 xpio_attr_xlate_tostr_hex(const uint32_t val, const xpio_pair_t *pairs,
349     char *buf, size_t buflen)
350 {
351 	return (snprintf(buf, buflen, "0x%x", val) < buflen);
352 }
353 
354 static bool
xpio_attr_xlate_tou32_hex(const char * str,const xpio_pair_t * pairs,uint32_t * outp)355 xpio_attr_xlate_tou32_hex(const char *str, const xpio_pair_t *pairs,
356     uint32_t *outp)
357 {
358 	char *eptr;
359 	unsigned long long l;
360 
361 	errno = 0;
362 	l = strtoull(str, &eptr, 0);
363 	if (errno != 0 || *eptr != '\0' || l > UINT32_MAX) {
364 		return (false);
365 	}
366 
367 	*outp = (uint32_t)l;
368 	return (true);
369 }
370 
371 static const xpio_translate_t xpio_attr_xlates[] = {
372 	/* zen_gpio(4D) attrs */
373 	{ ZEN_GPIO_ATTR_PAD_TYPE, zen_gpio_pad_pairs,
374 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
375 	{ ZEN_GPIO_ATTR_CAPS, zen_gpio_cap_pairs,
376 	    xpio_attr_xlate_tostr_bitfield, xpio_attr_xlate_tou32_bitfield },
377 	{ ZEN_GPIO_ATTR_OUTPUT_DRIVER, zen_gpio_driver_pairs,
378 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
379 	{ ZEN_GPIO_ATTR_OUTPUT, zen_gpio_output_pairs,
380 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
381 	{ ZEN_GPIO_ATTR_INPUT, zen_gpio_input_pairs,
382 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
383 	{ ZEN_GPIO_ATTR_VOLTAGE, zen_gpio_voltage_pairs,
384 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
385 	{ ZEN_GPIO_ATTR_PULL, zen_gpio_pull_pairs,
386 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
387 	{ ZEN_GPIO_ATTR_DRIVE_STRENGTH, zen_gpio_drive_pairs,
388 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
389 	{ ZEN_GPIO_ATTR_DEBOUNCE_MODE, zen_gpio_dbt_mode_pairs,
390 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
391 	{ ZEN_GPIO_ATTR_DEBOUNCE_UNIT, zen_gpio_dbt_unit_pairs,
392 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
393 	{ ZEN_GPIO_ATTR_DEBOUNCE_COUNT, NULL, xpio_attr_xlate_tostr_hex,
394 	    xpio_attr_xlate_tou32_hex },
395 	{ ZEN_GPIO_ATTR_TRIGGER_MODE, zen_gpio_trigger_mode_pairs,
396 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
397 	{ ZEN_GPIO_ATTR_STATUS, zen_gpio_status_pairs,
398 	    xpio_attr_xlate_tostr_bitfield, xpio_attr_xlate_tou32_bitfield },
399 	{ ZEN_GPIO_ATTR_RAW_REG, NULL, xpio_attr_xlate_tostr_hex,
400 	    xpio_attr_xlate_tou32_hex },
401 	/* gpio_sim(4D) attrs */
402 	{ GPIO_SIM_ATTR_OUTPUT, gpio_sim_output_pairs,
403 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
404 	{ GPIO_SIM_ATTR_INPUT, gpio_sim_input_pairs,
405 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
406 	{ GPIO_SIM_ATTR_PULL, gpio_sim_pull_pairs,
407 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
408 	{ GPIO_SIM_ATTR_VOLTAGE, gpio_sim_voltage_pairs,
409 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
410 	{ GPIO_SIM_ATTR_SPEED, gpio_sim_speed_pairs,
411 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
412 	/* pca953x(4D) attrs */
413 	{ PCA953X_GPIO_ATTR_INPUT, pca953x_input_pairs,
414 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
415 	{ PCA953X_GPIO_ATTR_OUTPUT, pca953x_output_pairs,
416 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
417 	{ PCA953X_GPIO_ATTR_POLARITY, pca953x_polarity_pairs,
418 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
419 	/* ltc4306(4D) attrs */
420 	{ LTC4306_GPIO_ATTR_INPUT, ltc4306_input_pairs,
421 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
422 	{ LTC4306_GPIO_ATTR_OUTPUT, ltc4306_output_pairs,
423 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct },
424 	{ LTC4306_GPIO_ATTR_OUTPUT_MODE, ltc4306_output_mode_pairs,
425 	    xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }
426 };
427 
428 bool
xpio_gpio_attr_xlate_uint32_to_str(xpio_gpio_info_t * gi,xpio_gpio_attr_t * attr,uint32_t val,char * buf,size_t buflen)429 xpio_gpio_attr_xlate_uint32_to_str(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr,
430     uint32_t val, char *buf, size_t buflen)
431 {
432 	const char *name = xpio_gpio_attr_name(gi, attr);
433 
434 	for (size_t i = 0; i < ARRAY_SIZE(xpio_attr_xlates); i++) {
435 		if (strcmp(name, xpio_attr_xlates[i].xt_name) != 0)
436 			continue;
437 
438 		return (xpio_attr_xlates[i].xt_xlate_tostr(val,
439 		    xpio_attr_xlates[i].xt_pairs, buf, buflen));
440 	}
441 
442 	return (false);
443 }
444 
445 bool
xpio_gpio_attr_xlate_to_str(xpio_gpio_info_t * gi,xpio_gpio_attr_t * attr,char * buf,size_t buflen)446 xpio_gpio_attr_xlate_to_str(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr,
447     char *buf, size_t buflen)
448 {
449 	uint32_t val;
450 
451 	if (!xpio_gpio_attr_value_uint32(attr, &val)) {
452 		return (false);
453 	}
454 
455 	return (xpio_gpio_attr_xlate_uint32_to_str(gi, attr, val, buf, buflen));
456 }
457 
458 xpio_gpio_attr_t *
xpio_gpio_attr_find(xpio_gpio_info_t * gi,const char * name)459 xpio_gpio_attr_find(xpio_gpio_info_t *gi, const char *name)
460 {
461 	nvpair_t *pair;
462 
463 	if (strcmp(name, KGPIO_ATTR_META) == 0) {
464 		return (NULL);
465 	}
466 
467 	if (nvlist_lookup_nvpair(gi->xgi_nvl, name, &pair) != 0) {
468 		return (NULL);
469 	}
470 
471 	switch (nvpair_type(pair)) {
472 	case DATA_TYPE_UINT32:
473 	case DATA_TYPE_STRING:
474 		break;
475 	default:
476 		return (NULL);
477 	}
478 
479 	return ((xpio_gpio_attr_t *)pair);
480 }
481 
482 xpio_gpio_attr_t *
xpio_gpio_attr_next(xpio_gpio_info_t * gi,xpio_gpio_attr_t * attr)483 xpio_gpio_attr_next(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr)
484 {
485 	nvpair_t *pair_in = (nvpair_t *)attr;
486 
487 	for (;;) {
488 		nvpair_t *next = nvlist_next_nvpair(gi->xgi_nvl, pair_in);
489 		if (next == NULL) {
490 			return (NULL);
491 		}
492 
493 		switch (nvpair_type(next)) {
494 		case DATA_TYPE_UINT32:
495 		case DATA_TYPE_STRING:
496 			break;
497 		default:
498 			pair_in = next;
499 			continue;
500 		}
501 
502 		if (strcmp(KGPIO_ATTR_META, nvpair_name(next)) == 0) {
503 			pair_in = next;
504 			continue;
505 		}
506 
507 		return ((xpio_gpio_attr_t *)next);
508 	}
509 }
510 
511 const char *
xpio_gpio_attr_name(xpio_gpio_info_t * gi,xpio_gpio_attr_t * attr)512 xpio_gpio_attr_name(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr)
513 {
514 	nvpair_t *pair = (nvpair_t *)attr;
515 	return (nvpair_name(pair));
516 }
517 
518 xpio_attr_type_t
xpio_gpio_attr_type(xpio_gpio_info_t * gi,xpio_gpio_attr_t * attr)519 xpio_gpio_attr_type(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr)
520 {
521 	nvpair_t *pair = (nvpair_t *)attr;
522 
523 	/*
524 	 * We should only have handed out an nvpair that matches these two types
525 	 * at this point.
526 	 */
527 	switch (nvpair_type(pair)) {
528 	case DATA_TYPE_UINT32:
529 		return (XPIO_ATTR_TYPE_UINT32);
530 	case DATA_TYPE_STRING:
531 		return (XPIO_ATTR_TYPE_STRING);
532 	default:
533 		abort();
534 	}
535 }
536 
537 static const char *
xpio_gpio_attr_type_name(xpio_attr_type_t type)538 xpio_gpio_attr_type_name(xpio_attr_type_t type)
539 {
540 	switch (type) {
541 	case XPIO_ATTR_TYPE_UINT32:
542 		return ("XPIO_ATTR_TYPE_UINT32");
543 	case XPIO_ATTR_TYPE_STRING:
544 		return ("XPIO_ATTR_TYPE_STRING");
545 	default:
546 		abort();
547 	}
548 }
549 
550 bool
xpio_gpio_attr_value_string(xpio_gpio_attr_t * attr,const char ** outp)551 xpio_gpio_attr_value_string(xpio_gpio_attr_t *attr, const char **outp)
552 {
553 	char *lookup;
554 
555 	if (nvpair_value_string((nvpair_t *)attr, &lookup) != 0) {
556 		return (false);
557 	}
558 
559 	*outp = lookup;
560 	return (true);
561 }
562 
563 bool
xpio_gpio_attr_value_uint32(xpio_gpio_attr_t * attr,uint32_t * outp)564 xpio_gpio_attr_value_uint32(xpio_gpio_attr_t *attr, uint32_t *outp)
565 {
566 	return (nvpair_value_uint32((nvpair_t *)attr, outp) == 0);
567 }
568 
569 void
xpio_gpio_attr_possible_string(xpio_gpio_info_t * gi,xpio_gpio_attr_t * attr,const char *** outp,uint_t * countp)570 xpio_gpio_attr_possible_string(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr,
571     const char ***outp, uint_t *countp)
572 {
573 	nvlist_t *meta_nvl, *attr_nvl;
574 	const char *key = nvpair_name((nvpair_t *)attr);
575 	char **strp;
576 
577 	*outp = NULL;
578 	*countp = 0;
579 
580 	if (nvlist_lookup_nvlist(gi->xgi_nvl, KGPIO_ATTR_META, &meta_nvl) !=
581 	    0) {
582 		return;
583 	}
584 
585 	if (nvlist_lookup_nvlist(meta_nvl, key, &attr_nvl) != 0) {
586 		return;
587 	}
588 
589 	if (nvlist_lookup_string_array(attr_nvl, KGPIO_ATTR_POS, &strp,
590 	    countp) != 0) {
591 		*outp = (const char **)strp;
592 	}
593 }
594 
595 void
xpio_gpio_attr_possible_uint32(xpio_gpio_info_t * gi,xpio_gpio_attr_t * attr,uint32_t ** outp,uint_t * countp)596 xpio_gpio_attr_possible_uint32(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr,
597     uint32_t **outp, uint_t *countp)
598 {
599 	nvlist_t *meta_nvl, *attr_nvl;
600 	const char *key = nvpair_name((nvpair_t *)attr);
601 
602 	*outp = NULL;
603 	*countp = 0;
604 
605 	if (nvlist_lookup_nvlist(gi->xgi_nvl, KGPIO_ATTR_META, &meta_nvl) !=
606 	    0) {
607 		return;
608 	}
609 
610 	if (nvlist_lookup_nvlist(meta_nvl, key, &attr_nvl) != 0) {
611 		return;
612 	}
613 
614 	(void) nvlist_lookup_uint32_array(attr_nvl, KGPIO_ATTR_POS, outp,
615 	    countp);
616 }
617 
618 xpio_attr_prot_t
xpio_gpio_attr_prot(xpio_gpio_info_t * gi,xpio_gpio_attr_t * attr)619 xpio_gpio_attr_prot(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr)
620 {
621 	uint32_t prot;
622 	nvlist_t *meta_nvl, *attr_nvl;
623 	const char *key = nvpair_name((nvpair_t *)attr);
624 
625 	if (nvlist_lookup_nvlist(gi->xgi_nvl, KGPIO_ATTR_META, &meta_nvl) !=
626 	    0) {
627 		return (XPIO_ATTR_PROT_RO);
628 	}
629 
630 	if (nvlist_lookup_nvlist(meta_nvl, key, &attr_nvl) != 0) {
631 		return (XPIO_ATTR_PROT_RO);
632 	}
633 
634 	if (nvlist_lookup_uint32(attr_nvl, KGPIO_ATTR_PROT, &prot) != 0) {
635 		return (XPIO_ATTR_PROT_RO);
636 	}
637 
638 	switch (prot) {
639 	case KGPIO_PROT_RW:
640 		return (XPIO_ATTR_PROT_RW);
641 	case KGPIO_PROT_RO:
642 	default:
643 		return (XPIO_ATTR_PROT_RO);
644 	}
645 }
646 
647 bool
xpio_gpio_attr_set_uint32(xpio_gpio_update_t * update,xpio_gpio_attr_t * attr,uint32_t val)648 xpio_gpio_attr_set_uint32(xpio_gpio_update_t *update, xpio_gpio_attr_t *attr,
649     uint32_t val)
650 {
651 	int ret;
652 	xpio_attr_type_t type = xpio_gpio_attr_type(update->xgo_gpio, attr);
653 	const char *key = xpio_gpio_attr_name(update->xgo_gpio, attr);
654 
655 	if (type != XPIO_ATTR_TYPE_UINT32) {
656 		return (xpio_update_error(update, XPIO_UPDATE_ERR_BAD_TYPE, 0,
657 		    "attribute type for %s is %s, not a uint32", key,
658 		    xpio_gpio_attr_type_name(type)));
659 	}
660 
661 	ret = nvlist_add_uint32(update->xgo_update, key, val);
662 	switch (ret) {
663 	case 0:
664 		return (xpio_update_success(update));
665 	case ENOMEM:
666 		return (xpio_update_error(update, XPIO_UPDATE_ERR_NO_MEM, ret,
667 		    "failed to allocate memory to insert attribute %s into "
668 		    "update structure", key));
669 	default:
670 		return (xpio_update_error(update, XPIO_UPDATE_ERR_INTERNAL, ret,
671 		    "unexpected internal error while trying to insert "
672 		    "attribute %s into update structure: %s", key,
673 		    strerror(ret)));
674 	}
675 }
676 
677 bool
xpio_gpio_attr_set_str(xpio_gpio_update_t * update,xpio_gpio_attr_t * attr,const char * val)678 xpio_gpio_attr_set_str(xpio_gpio_update_t *update, xpio_gpio_attr_t *attr,
679     const char *val)
680 {
681 	int ret;
682 	xpio_attr_type_t type = xpio_gpio_attr_type(update->xgo_gpio, attr);
683 	const char *key = xpio_gpio_attr_name(update->xgo_gpio, attr);
684 
685 	if (type != XPIO_ATTR_TYPE_STRING) {
686 		return (xpio_update_error(update, XPIO_UPDATE_ERR_BAD_TYPE, 0,
687 		    "attribute type for %s is %s, not a string", key,
688 		    xpio_gpio_attr_type_name(type)));
689 	}
690 
691 	ret = nvlist_add_string(update->xgo_update, key, val);
692 	switch (ret) {
693 	case 0:
694 		return (xpio_update_success(update));
695 	case ENOMEM:
696 		return (xpio_update_error(update, XPIO_UPDATE_ERR_NO_MEM, ret,
697 		    "failed to allocate memory to insert attribute %s into "
698 		    "update structure", key));
699 	default:
700 		return (xpio_update_error(update, XPIO_UPDATE_ERR_INTERNAL, ret,
701 		    "unexpected internal error while trying to insert "
702 		    "attribute %s into update structure: %s", key,
703 		    strerror(ret)));
704 	}
705 }
706 
707 /*
708  * This update path attempts to translate the passed in string into the
709  * appropriate attribute type. This is designed for tools that want to work in
710  * the more human values that we have for various GPIO attributes.
711  */
712 bool
xpio_gpio_attr_from_str(xpio_gpio_update_t * update,xpio_gpio_attr_t * attr,const char * raw_val)713 xpio_gpio_attr_from_str(xpio_gpio_update_t *update, xpio_gpio_attr_t *attr,
714     const char *raw_val)
715 {
716 	xpio_attr_type_t type = xpio_gpio_attr_type(update->xgo_gpio, attr);
717 	const char *key = xpio_gpio_attr_name(update->xgo_gpio, attr);
718 
719 	/*
720 	 * If the data type for this is a string, then we can just insert the
721 	 * value as is and there is no need for translation. Otherwise, we must
722 	 * look at the data type and perform the appropriate translation.
723 	 */
724 	if (type == XPIO_ATTR_TYPE_STRING) {
725 		return (xpio_gpio_attr_set_str(update, attr, raw_val));
726 	}
727 
728 	for (size_t i = 0; i < ARRAY_SIZE(xpio_attr_xlates); i++) {
729 		uint32_t u32;
730 
731 		if (strcmp(key, xpio_attr_xlates[i].xt_name) != 0)
732 			continue;
733 		if (!xpio_attr_xlates[i].xt_xlate_tou32(raw_val,
734 		    xpio_attr_xlates[i].xt_pairs, &u32)) {
735 			return (xpio_update_error(update,
736 			    XPIO_UPDATE_ERR_CANT_XLATE, 0, "failed to  "
737 			    "translate attribute %s value %s to a uint32",
738 			    key, raw_val));
739 		}
740 
741 		return (xpio_gpio_attr_set_uint32(update, attr, u32));
742 	}
743 
744 	return (xpio_update_error(update, XPIO_UPDATE_ERR_INTERNAL, ENOENT,
745 	    "missing internal translator for attr %s to type %s", key,
746 	    xpio_gpio_attr_type_name(type)));
747 
748 }
749 
750 xpio_gpio_attr_err_t *
xpio_gpio_attr_err_next(xpio_gpio_update_t * update,xpio_gpio_attr_err_t * cur)751 xpio_gpio_attr_err_next(xpio_gpio_update_t *update, xpio_gpio_attr_err_t *cur)
752 {
753 	nvpair_t *pair_in = (nvpair_t *)cur;
754 
755 	if (update->xgo_err_nvl == NULL) {
756 		return (NULL);
757 	}
758 
759 	for (;;) {
760 		nvpair_t *next = nvlist_next_nvpair(update->xgo_err_nvl,
761 		    pair_in);
762 		if (next == NULL) {
763 			return (NULL);
764 		}
765 
766 		if (nvpair_type(next) != DATA_TYPE_UINT32) {
767 			pair_in = next;
768 			continue;
769 		}
770 
771 		return ((xpio_gpio_attr_err_t *)next);
772 	}
773 }
774 
775 const char *
xpio_gpio_attr_err_name(xpio_gpio_attr_err_t * err)776 xpio_gpio_attr_err_name(xpio_gpio_attr_err_t *err)
777 {
778 	nvpair_t *pair = (nvpair_t *)err;
779 	return (nvpair_name(pair));
780 }
781 
782 xpio_update_err_t
xpio_gpio_attr_err_err(xpio_gpio_attr_err_t * err)783 xpio_gpio_attr_err_err(xpio_gpio_attr_err_t *err)
784 {
785 	uint32_t val;
786 	nvpair_t *pair = (nvpair_t *)err;
787 
788 	if (nvpair_value_uint32(pair, &val) != 0) {
789 		return (XPIO_UPDATE_ERR_INTERNAL);
790 	}
791 
792 	switch (val) {
793 	case KGPIO_ATTR_ERR_OK:
794 		return (XPIO_UPDATE_ERR_OK);
795 	case KGPIO_ATTR_ERR_ATTR_RO:
796 		return (XPIO_UPDATE_ERR_RO);
797 	case KGPIO_ATTR_ERR_UNKNOWN_ATTR:
798 		return (XPIO_UPDATE_ERR_UNKNOWN_ATTR);
799 	case KGPIO_ATTR_ERR_BAD_TYPE:
800 		return (XPIO_UPDATE_ERR_BAD_TYPE);
801 	case KGPIO_ATTR_ERR_UNKNOWN_VAL:
802 		return (XPIO_UPDATE_ERR_CANT_XLATE);
803 	case KGPIO_ATTR_ERR_CANT_APPLY_VAL:
804 		return (XPIO_UPDATE_ERR_CANT_APPLY_VAL);
805 	default:
806 		return (XPIO_UPDATE_ERR_INTERNAL);
807 	}
808 }
809