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