xref: /illumos-gate/usr/src/cmd/gpioadm/gpioadm_gpio.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 #include <string.h>
17*fd71220bSRobert Mustacchi #include <err.h>
18*fd71220bSRobert Mustacchi #include <stdlib.h>
19*fd71220bSRobert Mustacchi #include <stdarg.h>
20*fd71220bSRobert Mustacchi #include <ofmt.h>
21*fd71220bSRobert Mustacchi #include <libdevinfo.h>
22*fd71220bSRobert Mustacchi #include <strings.h>
23*fd71220bSRobert Mustacchi #include <sys/debug.h>
24*fd71220bSRobert Mustacchi 
25*fd71220bSRobert Mustacchi #include "gpioadm.h"
26*fd71220bSRobert Mustacchi 
27*fd71220bSRobert Mustacchi static void
gpioadm_gpio_attr_get_usage(FILE * f)28*fd71220bSRobert Mustacchi gpioadm_gpio_attr_get_usage(FILE *f)
29*fd71220bSRobert Mustacchi {
30*fd71220bSRobert Mustacchi 	(void) fprintf(f, "\tgpioadm gpio attr get [-H] [-o field[,...] [-p]] "
31*fd71220bSRobert Mustacchi 	    "controller/gpio [filter...]\n");
32*fd71220bSRobert Mustacchi }
33*fd71220bSRobert Mustacchi 
34*fd71220bSRobert Mustacchi static void __PRINTFLIKE(1)
gpioadm_gpio_attr_get_help(const char * fmt,...)35*fd71220bSRobert Mustacchi gpioadm_gpio_attr_get_help(const char *fmt, ...)
36*fd71220bSRobert Mustacchi {
37*fd71220bSRobert Mustacchi 	if (fmt != NULL) {
38*fd71220bSRobert Mustacchi 		va_list ap;
39*fd71220bSRobert Mustacchi 
40*fd71220bSRobert Mustacchi 		va_start(ap, fmt);
41*fd71220bSRobert Mustacchi 		vwarnx(fmt, ap);
42*fd71220bSRobert Mustacchi 		va_end(ap);
43*fd71220bSRobert Mustacchi 	}
44*fd71220bSRobert Mustacchi 
45*fd71220bSRobert Mustacchi 	(void) fprintf(stderr, "Usage:  gpioadm gpio attr get [-H] "
46*fd71220bSRobert Mustacchi 	    "[-o field[,...] [-p]] controller/gpio\n\t\t\t      [filter...]\n");
47*fd71220bSRobert Mustacchi 	(void) fprintf(stderr, "\nList attributes of a specific GPIO\n\n"
48*fd71220bSRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
49*fd71220bSRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
50*fd71220bSRobert Mustacchi 	    "\t-p\t\tparsable output (requires -o)\n\n"
51*fd71220bSRobert Mustacchi 	    "The following fields are supported:\n"
52*fd71220bSRobert Mustacchi 	    "\tattr\t\tthe name of the attribute\n"
53*fd71220bSRobert Mustacchi 	    "\tvalue\t\tthe human-readable value of the attribute\n"
54*fd71220bSRobert Mustacchi 	    "\traw\t\tan untranslated value of the attribute (e.g. "
55*fd71220bSRobert Mustacchi 	    "underlying\n\t\t\tenum)\n"
56*fd71220bSRobert Mustacchi 	    "\tperm\t\tthe permissions of the attribute\n"
57*fd71220bSRobert Mustacchi 	    "\tpossible\tthe possible values the attribute may take\n\n"
58*fd71220bSRobert Mustacchi 	    "Supported filters are the names of attributes. An attribute "
59*fd71220bSRobert Mustacchi 	    "will be printed\nas long as it matches a single filter (they "
60*fd71220bSRobert Mustacchi 	    "function as an OR). If any\nfilter does not match, then a non-"
61*fd71220bSRobert Mustacchi 	    "zero exit status is returned.\n");
62*fd71220bSRobert Mustacchi }
63*fd71220bSRobert Mustacchi 
64*fd71220bSRobert Mustacchi typedef enum gpioadm_gpio_attr_get_otype {
65*fd71220bSRobert Mustacchi 	GPIOADM_GPIO_ATTR_GET_ATTR,
66*fd71220bSRobert Mustacchi 	GPIOADM_GPIO_ATTR_GET_VALUE,
67*fd71220bSRobert Mustacchi 	GPIOADM_GPIO_ATTR_GET_RAW,
68*fd71220bSRobert Mustacchi 	GPIOADM_GPIO_ATTR_GET_PERM,
69*fd71220bSRobert Mustacchi 	GPIOADM_GPIO_ATTR_GET_POSSIBLE,
70*fd71220bSRobert Mustacchi } gpioadm_gpio_attr_get_otype_t;
71*fd71220bSRobert Mustacchi 
72*fd71220bSRobert Mustacchi typedef struct gpioadm_gpio_attr_get_ofmt {
73*fd71220bSRobert Mustacchi 	xpio_gpio_info_t *ggag_info;
74*fd71220bSRobert Mustacchi 	xpio_gpio_attr_t *ggag_attr;
75*fd71220bSRobert Mustacchi } gpioadm_gpio_attr_get_ofmt_t;
76*fd71220bSRobert Mustacchi 
77*fd71220bSRobert Mustacchi static boolean_t
gpioadm_gpio_attr_get_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)78*fd71220bSRobert Mustacchi gpioadm_gpio_attr_get_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
79*fd71220bSRobert Mustacchi {
80*fd71220bSRobert Mustacchi 	const char *str;
81*fd71220bSRobert Mustacchi 	uint32_t u32;
82*fd71220bSRobert Mustacchi 	uint32_t *u32_arr;
83*fd71220bSRobert Mustacchi 	const char **str_arr;
84*fd71220bSRobert Mustacchi 	uint_t count;
85*fd71220bSRobert Mustacchi 	uintptr_t off = 0;
86*fd71220bSRobert Mustacchi 
87*fd71220bSRobert Mustacchi 	gpioadm_gpio_attr_get_ofmt_t *ggag = ofarg->ofmt_cbarg;
88*fd71220bSRobert Mustacchi 	xpio_gpio_info_t *info = ggag->ggag_info;
89*fd71220bSRobert Mustacchi 	xpio_gpio_attr_t *attr = ggag->ggag_attr;
90*fd71220bSRobert Mustacchi 
91*fd71220bSRobert Mustacchi 	switch (ofarg->ofmt_id) {
92*fd71220bSRobert Mustacchi 	case GPIOADM_GPIO_ATTR_GET_ATTR:
93*fd71220bSRobert Mustacchi 		if (strlcpy(buf, xpio_gpio_attr_name(info, attr), buflen) >=
94*fd71220bSRobert Mustacchi 		    buflen) {
95*fd71220bSRobert Mustacchi 			return (B_FALSE);
96*fd71220bSRobert Mustacchi 		}
97*fd71220bSRobert Mustacchi 		break;
98*fd71220bSRobert Mustacchi 	case GPIOADM_GPIO_ATTR_GET_VALUE:
99*fd71220bSRobert Mustacchi 		switch (xpio_gpio_attr_type(info, attr)) {
100*fd71220bSRobert Mustacchi 		case XPIO_ATTR_TYPE_STRING:
101*fd71220bSRobert Mustacchi 			if (!xpio_gpio_attr_value_string(attr, &str)) {
102*fd71220bSRobert Mustacchi 				return (B_FALSE);
103*fd71220bSRobert Mustacchi 			}
104*fd71220bSRobert Mustacchi 
105*fd71220bSRobert Mustacchi 			if (strlcpy(buf, str, buflen) >= buflen) {
106*fd71220bSRobert Mustacchi 				return (B_FALSE);
107*fd71220bSRobert Mustacchi 			}
108*fd71220bSRobert Mustacchi 			break;
109*fd71220bSRobert Mustacchi 		case XPIO_ATTR_TYPE_UINT32:
110*fd71220bSRobert Mustacchi 			if (!xpio_gpio_attr_xlate_to_str(info, attr, buf,
111*fd71220bSRobert Mustacchi 			    buflen)) {
112*fd71220bSRobert Mustacchi 				return (B_FALSE);
113*fd71220bSRobert Mustacchi 			}
114*fd71220bSRobert Mustacchi 			break;
115*fd71220bSRobert Mustacchi 		}
116*fd71220bSRobert Mustacchi 		break;
117*fd71220bSRobert Mustacchi 	case GPIOADM_GPIO_ATTR_GET_RAW:
118*fd71220bSRobert Mustacchi 		switch (xpio_gpio_attr_type(info, attr)) {
119*fd71220bSRobert Mustacchi 		case XPIO_ATTR_TYPE_STRING:
120*fd71220bSRobert Mustacchi 			if (!xpio_gpio_attr_value_string(attr, &str)) {
121*fd71220bSRobert Mustacchi 				return (B_FALSE);
122*fd71220bSRobert Mustacchi 			}
123*fd71220bSRobert Mustacchi 
124*fd71220bSRobert Mustacchi 			if (strlcpy(buf, str, buflen) >= buflen) {
125*fd71220bSRobert Mustacchi 				return (B_FALSE);
126*fd71220bSRobert Mustacchi 			}
127*fd71220bSRobert Mustacchi 			break;
128*fd71220bSRobert Mustacchi 		case XPIO_ATTR_TYPE_UINT32:
129*fd71220bSRobert Mustacchi 			if (!xpio_gpio_attr_value_uint32(attr, &u32)) {
130*fd71220bSRobert Mustacchi 				return (B_FALSE);
131*fd71220bSRobert Mustacchi 			}
132*fd71220bSRobert Mustacchi 
133*fd71220bSRobert Mustacchi 			if (snprintf(buf, buflen, "0x%x", u32) >= buflen) {
134*fd71220bSRobert Mustacchi 				return (B_FALSE);
135*fd71220bSRobert Mustacchi 			}
136*fd71220bSRobert Mustacchi 			break;
137*fd71220bSRobert Mustacchi 		}
138*fd71220bSRobert Mustacchi 		break;
139*fd71220bSRobert Mustacchi 	case GPIOADM_GPIO_ATTR_GET_PERM:
140*fd71220bSRobert Mustacchi 		switch (xpio_gpio_attr_prot(info, attr)) {
141*fd71220bSRobert Mustacchi 		case XPIO_ATTR_PROT_RO:
142*fd71220bSRobert Mustacchi 			if (strlcpy(buf, "r-", buflen) >= buflen) {
143*fd71220bSRobert Mustacchi 				return (B_FALSE);
144*fd71220bSRobert Mustacchi 			}
145*fd71220bSRobert Mustacchi 			break;
146*fd71220bSRobert Mustacchi 		case XPIO_ATTR_PROT_RW:
147*fd71220bSRobert Mustacchi 			if (strlcpy(buf, "rw", buflen) >= buflen) {
148*fd71220bSRobert Mustacchi 				return (B_FALSE);
149*fd71220bSRobert Mustacchi 			}
150*fd71220bSRobert Mustacchi 			break;
151*fd71220bSRobert Mustacchi 		}
152*fd71220bSRobert Mustacchi 		break;
153*fd71220bSRobert Mustacchi 	case GPIOADM_GPIO_ATTR_GET_POSSIBLE:
154*fd71220bSRobert Mustacchi 		switch (xpio_gpio_attr_type(info, attr)) {
155*fd71220bSRobert Mustacchi 		case XPIO_ATTR_TYPE_STRING:
156*fd71220bSRobert Mustacchi 			xpio_gpio_attr_possible_string(info, attr, &str_arr,
157*fd71220bSRobert Mustacchi 			    &count);
158*fd71220bSRobert Mustacchi 			for (uint_t i = 0; i < count; i++) {
159*fd71220bSRobert Mustacchi 				int len = snprintf(buf + off, buflen - off,
160*fd71220bSRobert Mustacchi 				    "%s%s", i > 0 ? "," : "", str_arr[i]);
161*fd71220bSRobert Mustacchi 				if (len >= (buflen - off)) {
162*fd71220bSRobert Mustacchi 					return (B_FALSE);
163*fd71220bSRobert Mustacchi 				}
164*fd71220bSRobert Mustacchi 				off += len;
165*fd71220bSRobert Mustacchi 			}
166*fd71220bSRobert Mustacchi 			break;
167*fd71220bSRobert Mustacchi 		case XPIO_ATTR_TYPE_UINT32:
168*fd71220bSRobert Mustacchi 			xpio_gpio_attr_possible_uint32(info, attr, &u32_arr,
169*fd71220bSRobert Mustacchi 			    &count);
170*fd71220bSRobert Mustacchi 			for (uint_t i = 0; i < count; i++) {
171*fd71220bSRobert Mustacchi 				char xlate[512];
172*fd71220bSRobert Mustacchi 				if (!xpio_gpio_attr_xlate_uint32_to_str(info,
173*fd71220bSRobert Mustacchi 				    attr, u32_arr[i], xlate, sizeof (xlate))) {
174*fd71220bSRobert Mustacchi 					return (B_FALSE);
175*fd71220bSRobert Mustacchi 				}
176*fd71220bSRobert Mustacchi 				int len = snprintf(buf + off, buflen - off,
177*fd71220bSRobert Mustacchi 				    "%s%s", i > 0 ? "," : "", xlate);
178*fd71220bSRobert Mustacchi 				if (len >= (buflen - off)) {
179*fd71220bSRobert Mustacchi 					return (B_FALSE);
180*fd71220bSRobert Mustacchi 				}
181*fd71220bSRobert Mustacchi 				off += len;
182*fd71220bSRobert Mustacchi 			}
183*fd71220bSRobert Mustacchi 			break;
184*fd71220bSRobert Mustacchi 		}
185*fd71220bSRobert Mustacchi 		break;
186*fd71220bSRobert Mustacchi 	default:
187*fd71220bSRobert Mustacchi 		abort();
188*fd71220bSRobert Mustacchi 	}
189*fd71220bSRobert Mustacchi 
190*fd71220bSRobert Mustacchi 	return (B_TRUE);
191*fd71220bSRobert Mustacchi }
192*fd71220bSRobert Mustacchi 
193*fd71220bSRobert Mustacchi static const char *gpioadm_gpio_attr_get_fields = "attr,perm,value,possible";
194*fd71220bSRobert Mustacchi static const ofmt_field_t gpioadm_gpio_attr_get_ofmt[] = {
195*fd71220bSRobert Mustacchi 	{ "ATTR", 22, GPIOADM_GPIO_ATTR_GET_ATTR,
196*fd71220bSRobert Mustacchi 	    gpioadm_gpio_attr_get_ofmt_cb },
197*fd71220bSRobert Mustacchi 	{ "PERM", 6, GPIOADM_GPIO_ATTR_GET_PERM,
198*fd71220bSRobert Mustacchi 	    gpioadm_gpio_attr_get_ofmt_cb },
199*fd71220bSRobert Mustacchi 	{ "VALUE", 24, GPIOADM_GPIO_ATTR_GET_VALUE,
200*fd71220bSRobert Mustacchi 	    gpioadm_gpio_attr_get_ofmt_cb },
201*fd71220bSRobert Mustacchi 	{ "RAW", 16, GPIOADM_GPIO_ATTR_GET_RAW,
202*fd71220bSRobert Mustacchi 	    gpioadm_gpio_attr_get_ofmt_cb },
203*fd71220bSRobert Mustacchi 	{ "POSSIBLE", 24, GPIOADM_GPIO_ATTR_GET_POSSIBLE,
204*fd71220bSRobert Mustacchi 	    gpioadm_gpio_attr_get_ofmt_cb },
205*fd71220bSRobert Mustacchi 	{ NULL, 0, 0, NULL }
206*fd71220bSRobert Mustacchi };
207*fd71220bSRobert Mustacchi 
208*fd71220bSRobert Mustacchi static int
gpioadm_gpio_attr_get(int argc,char * argv[])209*fd71220bSRobert Mustacchi gpioadm_gpio_attr_get(int argc, char *argv[])
210*fd71220bSRobert Mustacchi {
211*fd71220bSRobert Mustacchi 	int c, ret;
212*fd71220bSRobert Mustacchi 	uint_t flags = 0;
213*fd71220bSRobert Mustacchi 	boolean_t parse = B_FALSE;
214*fd71220bSRobert Mustacchi 	const char *fields = NULL, *target = NULL;
215*fd71220bSRobert Mustacchi 	ofmt_status_t oferr;
216*fd71220bSRobert Mustacchi 	ofmt_handle_t ofmt;
217*fd71220bSRobert Mustacchi 	xpio_ctrl_t *ctrl;
218*fd71220bSRobert Mustacchi 	xpio_gpio_info_t *gpio;
219*fd71220bSRobert Mustacchi 	bool *filts = NULL;
220*fd71220bSRobert Mustacchi 
221*fd71220bSRobert Mustacchi 	while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
222*fd71220bSRobert Mustacchi 		switch (c) {
223*fd71220bSRobert Mustacchi 		case 'H':
224*fd71220bSRobert Mustacchi 			flags |= OFMT_NOHEADER;
225*fd71220bSRobert Mustacchi 			break;
226*fd71220bSRobert Mustacchi 		case 'o':
227*fd71220bSRobert Mustacchi 			fields = optarg;
228*fd71220bSRobert Mustacchi 			break;
229*fd71220bSRobert Mustacchi 		case 'p':
230*fd71220bSRobert Mustacchi 			parse = B_TRUE;
231*fd71220bSRobert Mustacchi 			flags |= OFMT_PARSABLE;
232*fd71220bSRobert Mustacchi 			break;
233*fd71220bSRobert Mustacchi 		case ':':
234*fd71220bSRobert Mustacchi 			gpioadm_gpio_attr_get_help("option -%c requires an "
235*fd71220bSRobert Mustacchi 			    "argument", optopt);
236*fd71220bSRobert Mustacchi 			exit(EXIT_USAGE);
237*fd71220bSRobert Mustacchi 		case '?':
238*fd71220bSRobert Mustacchi 			gpioadm_gpio_attr_get_help("unknown option: -%c",
239*fd71220bSRobert Mustacchi 			    optopt);
240*fd71220bSRobert Mustacchi 			exit(EXIT_USAGE);
241*fd71220bSRobert Mustacchi 		}
242*fd71220bSRobert Mustacchi 	}
243*fd71220bSRobert Mustacchi 
244*fd71220bSRobert Mustacchi 	if (parse && fields == NULL) {
245*fd71220bSRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
246*fd71220bSRobert Mustacchi 	}
247*fd71220bSRobert Mustacchi 
248*fd71220bSRobert Mustacchi 	if (!parse) {
249*fd71220bSRobert Mustacchi 		flags |= OFMT_WRAP;
250*fd71220bSRobert Mustacchi 	}
251*fd71220bSRobert Mustacchi 
252*fd71220bSRobert Mustacchi 	if (fields == NULL) {
253*fd71220bSRobert Mustacchi 		fields = gpioadm_gpio_attr_get_fields;
254*fd71220bSRobert Mustacchi 	}
255*fd71220bSRobert Mustacchi 
256*fd71220bSRobert Mustacchi 	argc -= optind;
257*fd71220bSRobert Mustacchi 	argv += optind;
258*fd71220bSRobert Mustacchi 	if (argc == 0) {
259*fd71220bSRobert Mustacchi 		errx(EXIT_FAILURE, "missing required controller and gpio");
260*fd71220bSRobert Mustacchi 	}
261*fd71220bSRobert Mustacchi 	target = argv[0];
262*fd71220bSRobert Mustacchi 	argc--;
263*fd71220bSRobert Mustacchi 	argv++;
264*fd71220bSRobert Mustacchi 
265*fd71220bSRobert Mustacchi 	if (argc > 0) {
266*fd71220bSRobert Mustacchi 		filts = calloc(argc, sizeof (bool));
267*fd71220bSRobert Mustacchi 		if (filts == NULL) {
268*fd71220bSRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
269*fd71220bSRobert Mustacchi 			    "filter tracking");
270*fd71220bSRobert Mustacchi 		}
271*fd71220bSRobert Mustacchi 	}
272*fd71220bSRobert Mustacchi 	oferr = ofmt_open(fields, gpioadm_gpio_attr_get_ofmt, flags, 0,
273*fd71220bSRobert Mustacchi 	    &ofmt);
274*fd71220bSRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, gpioadm_ofmt_errx, warnx);
275*fd71220bSRobert Mustacchi 
276*fd71220bSRobert Mustacchi 	gpioadm_ctrl_gpio_init(target, &ctrl, &gpio);
277*fd71220bSRobert Mustacchi 
278*fd71220bSRobert Mustacchi 	for (xpio_gpio_attr_t *attr = xpio_gpio_attr_next(gpio, NULL);
279*fd71220bSRobert Mustacchi 	    attr != NULL; attr = xpio_gpio_attr_next(gpio, attr)) {
280*fd71220bSRobert Mustacchi 		gpioadm_gpio_attr_get_ofmt_t ggag;
281*fd71220bSRobert Mustacchi 
282*fd71220bSRobert Mustacchi 		if (argc > 0) {
283*fd71220bSRobert Mustacchi 			const char *aname = xpio_gpio_attr_name(gpio, attr);
284*fd71220bSRobert Mustacchi 			bool match = false;
285*fd71220bSRobert Mustacchi 			for (int i = 0; i < argc; i++) {
286*fd71220bSRobert Mustacchi 				if (strcmp(argv[i], aname) == 0) {
287*fd71220bSRobert Mustacchi 					match = true;
288*fd71220bSRobert Mustacchi 					filts[i] = true;
289*fd71220bSRobert Mustacchi 				}
290*fd71220bSRobert Mustacchi 			}
291*fd71220bSRobert Mustacchi 
292*fd71220bSRobert Mustacchi 			if (!match) {
293*fd71220bSRobert Mustacchi 				continue;
294*fd71220bSRobert Mustacchi 			}
295*fd71220bSRobert Mustacchi 		}
296*fd71220bSRobert Mustacchi 
297*fd71220bSRobert Mustacchi 		ggag.ggag_info = gpio;
298*fd71220bSRobert Mustacchi 		ggag.ggag_attr = attr;
299*fd71220bSRobert Mustacchi 		ofmt_print(ofmt, &ggag);
300*fd71220bSRobert Mustacchi 	}
301*fd71220bSRobert Mustacchi 
302*fd71220bSRobert Mustacchi 	ret = EXIT_SUCCESS;
303*fd71220bSRobert Mustacchi 	for (int i = 0; i < argc; i++) {
304*fd71220bSRobert Mustacchi 		if (!filts[i]) {
305*fd71220bSRobert Mustacchi 			warnx("filter '%s' did not match any attributes",
306*fd71220bSRobert Mustacchi 			    argv[i]);
307*fd71220bSRobert Mustacchi 			ret = EXIT_FAILURE;
308*fd71220bSRobert Mustacchi 		}
309*fd71220bSRobert Mustacchi 	}
310*fd71220bSRobert Mustacchi 
311*fd71220bSRobert Mustacchi 	free(filts);
312*fd71220bSRobert Mustacchi 	return (ret);
313*fd71220bSRobert Mustacchi }
314*fd71220bSRobert Mustacchi 
315*fd71220bSRobert Mustacchi static void
gpioadm_gpio_attr_set_usage(FILE * f)316*fd71220bSRobert Mustacchi gpioadm_gpio_attr_set_usage(FILE *f)
317*fd71220bSRobert Mustacchi {
318*fd71220bSRobert Mustacchi 	(void) fprintf(f, "\tgpioadm gpio attr set controller/gpio attr=value "
319*fd71220bSRobert Mustacchi 	    "[attr=value...]\n");
320*fd71220bSRobert Mustacchi }
321*fd71220bSRobert Mustacchi 
322*fd71220bSRobert Mustacchi static void __PRINTFLIKE(1)
gpioadm_gpio_attr_set_help(const char * fmt,...)323*fd71220bSRobert Mustacchi gpioadm_gpio_attr_set_help(const char *fmt, ...)
324*fd71220bSRobert Mustacchi {
325*fd71220bSRobert Mustacchi 	if (fmt != NULL) {
326*fd71220bSRobert Mustacchi 		va_list ap;
327*fd71220bSRobert Mustacchi 
328*fd71220bSRobert Mustacchi 		va_start(ap, fmt);
329*fd71220bSRobert Mustacchi 		vwarnx(fmt, ap);
330*fd71220bSRobert Mustacchi 		va_end(ap);
331*fd71220bSRobert Mustacchi 	}
332*fd71220bSRobert Mustacchi 
333*fd71220bSRobert Mustacchi 	(void) fprintf(stderr, "Usage:  gpioadm gpio attr set controller/gpio "
334*fd71220bSRobert Mustacchi 	    "attr=value [attr=value...]\n");
335*fd71220bSRobert Mustacchi 	(void) fprintf(stderr, "\nSets the attributes of a single GPIO. "
336*fd71220bSRobert Mustacchi 	    "All specified attributes are\napplied at once.\n");
337*fd71220bSRobert Mustacchi }
338*fd71220bSRobert Mustacchi 
339*fd71220bSRobert Mustacchi static int
gpioadm_gpio_attr_set(int argc,char * argv[])340*fd71220bSRobert Mustacchi gpioadm_gpio_attr_set(int argc, char *argv[])
341*fd71220bSRobert Mustacchi {
342*fd71220bSRobert Mustacchi 	int c;
343*fd71220bSRobert Mustacchi 	const char *target;
344*fd71220bSRobert Mustacchi 	xpio_ctrl_t *ctrl;
345*fd71220bSRobert Mustacchi 	xpio_gpio_info_t *gpio;
346*fd71220bSRobert Mustacchi 	xpio_gpio_update_t *update;
347*fd71220bSRobert Mustacchi 
348*fd71220bSRobert Mustacchi 	while ((c = getopt(argc, argv, ":")) != -1) {
349*fd71220bSRobert Mustacchi 		switch (c) {
350*fd71220bSRobert Mustacchi 		case ':':
351*fd71220bSRobert Mustacchi 			gpioadm_gpio_attr_set_help("option -%c requires an "
352*fd71220bSRobert Mustacchi 			    "argument", optopt);
353*fd71220bSRobert Mustacchi 			exit(EXIT_USAGE);
354*fd71220bSRobert Mustacchi 		case '?':
355*fd71220bSRobert Mustacchi 			gpioadm_gpio_attr_set_help("unknown option: -%c",
356*fd71220bSRobert Mustacchi 			    optopt);
357*fd71220bSRobert Mustacchi 			exit(EXIT_USAGE);
358*fd71220bSRobert Mustacchi 		}
359*fd71220bSRobert Mustacchi 	}
360*fd71220bSRobert Mustacchi 
361*fd71220bSRobert Mustacchi 	argc -= optind;
362*fd71220bSRobert Mustacchi 	argv += optind;
363*fd71220bSRobert Mustacchi 
364*fd71220bSRobert Mustacchi 	if (argc == 0) {
365*fd71220bSRobert Mustacchi 		errx(EXIT_USAGE, "missing required controller/gpio target");
366*fd71220bSRobert Mustacchi 	}
367*fd71220bSRobert Mustacchi 
368*fd71220bSRobert Mustacchi 	if (argc == 1) {
369*fd71220bSRobert Mustacchi 		errx(EXIT_USAGE, "missing required attribute settings");
370*fd71220bSRobert Mustacchi 	}
371*fd71220bSRobert Mustacchi 
372*fd71220bSRobert Mustacchi 	target = argv[0];
373*fd71220bSRobert Mustacchi 	gpioadm_ctrl_gpio_init(target, &ctrl, &gpio);
374*fd71220bSRobert Mustacchi 	if (!xpio_gpio_update_init(gpioadm.gpio_xpio, gpio, &update)) {
375*fd71220bSRobert Mustacchi 		gpioadm_fatal("failed to initialize update");
376*fd71220bSRobert Mustacchi 	}
377*fd71220bSRobert Mustacchi 
378*fd71220bSRobert Mustacchi 	for (int i = 1; i < argc; i++) {
379*fd71220bSRobert Mustacchi 		char *eq = strchr(argv[i], '=');
380*fd71220bSRobert Mustacchi 		const char *name, *value;
381*fd71220bSRobert Mustacchi 		xpio_gpio_attr_t *attr;
382*fd71220bSRobert Mustacchi 
383*fd71220bSRobert Mustacchi 		if (eq == NULL) {
384*fd71220bSRobert Mustacchi 			errx(EXIT_FAILURE, "invalid attribute: missing equals "
385*fd71220bSRobert Mustacchi 			    "sign for value: %s", argv[i]);
386*fd71220bSRobert Mustacchi 		}
387*fd71220bSRobert Mustacchi 		name = argv[i];
388*fd71220bSRobert Mustacchi 		value = eq + 1;
389*fd71220bSRobert Mustacchi 		*eq = '\0';
390*fd71220bSRobert Mustacchi 
391*fd71220bSRobert Mustacchi 		attr = xpio_gpio_attr_find(gpio, name);
392*fd71220bSRobert Mustacchi 		if (attr == NULL) {
393*fd71220bSRobert Mustacchi 			errx(EXIT_FAILURE, "invalid attribute: no attribute "
394*fd71220bSRobert Mustacchi 			    "named %s exists for GPIO %s", name, target);
395*fd71220bSRobert Mustacchi 		}
396*fd71220bSRobert Mustacchi 
397*fd71220bSRobert Mustacchi 		if (!xpio_gpio_attr_from_str(update, attr, value)) {
398*fd71220bSRobert Mustacchi 			gpioadm_update_fatal(update, "failed to set attribute "
399*fd71220bSRobert Mustacchi 			    "%s to %s on GPIO %s", name, value, target);
400*fd71220bSRobert Mustacchi 		}
401*fd71220bSRobert Mustacchi 	}
402*fd71220bSRobert Mustacchi 
403*fd71220bSRobert Mustacchi 	if (!xpio_gpio_update(ctrl, update)) {
404*fd71220bSRobert Mustacchi 		if (xpio_err(gpioadm.gpio_xpio) != XPIO_ERR_BAD_UPDATE) {
405*fd71220bSRobert Mustacchi 			gpioadm_fatal("failed to update GPIO %s", target);
406*fd71220bSRobert Mustacchi 		}
407*fd71220bSRobert Mustacchi 
408*fd71220bSRobert Mustacchi 		gpioadm_warn("failed to update GPIO %s", target);
409*fd71220bSRobert Mustacchi 
410*fd71220bSRobert Mustacchi 		for (xpio_gpio_attr_err_t *err =
411*fd71220bSRobert Mustacchi 		    xpio_gpio_attr_err_next(update, NULL); err != NULL;
412*fd71220bSRobert Mustacchi 		    err = xpio_gpio_attr_err_next(update, err)) {
413*fd71220bSRobert Mustacchi 			xpio_update_err_t uerr = xpio_gpio_attr_err_err(err);
414*fd71220bSRobert Mustacchi 
415*fd71220bSRobert Mustacchi 			(void) fprintf(stderr, "\tattribute %s -- %s (0x%x)\n",
416*fd71220bSRobert Mustacchi 			    xpio_gpio_attr_err_name(err),
417*fd71220bSRobert Mustacchi 			    xpio_update_err2str(update, uerr), uerr);
418*fd71220bSRobert Mustacchi 		}
419*fd71220bSRobert Mustacchi 	}
420*fd71220bSRobert Mustacchi 
421*fd71220bSRobert Mustacchi 	return (EXIT_SUCCESS);
422*fd71220bSRobert Mustacchi }
423*fd71220bSRobert Mustacchi 
424*fd71220bSRobert Mustacchi static const gpioadm_cmdtab_t gpioadm_cmds_gpio_attr[] = {
425*fd71220bSRobert Mustacchi 	{ "get", gpioadm_gpio_attr_get, gpioadm_gpio_attr_get_usage },
426*fd71220bSRobert Mustacchi 	{ "set", gpioadm_gpio_attr_set, gpioadm_gpio_attr_set_usage },
427*fd71220bSRobert Mustacchi 	{ NULL, NULL, NULL }
428*fd71220bSRobert Mustacchi };
429*fd71220bSRobert Mustacchi 
430*fd71220bSRobert Mustacchi static void
gpioadm_gpio_attr_usage(FILE * f)431*fd71220bSRobert Mustacchi gpioadm_gpio_attr_usage(FILE *f)
432*fd71220bSRobert Mustacchi {
433*fd71220bSRobert Mustacchi 	gpioadm_walk_usage(gpioadm_cmds_gpio_attr, f);
434*fd71220bSRobert Mustacchi }
435*fd71220bSRobert Mustacchi 
436*fd71220bSRobert Mustacchi static int
gpioadm_gpio_attr(int argc,char * argv[])437*fd71220bSRobert Mustacchi gpioadm_gpio_attr(int argc, char *argv[])
438*fd71220bSRobert Mustacchi {
439*fd71220bSRobert Mustacchi 	return (gpioadm_walk_tab(gpioadm_cmds_gpio_attr, argc, argv));
440*fd71220bSRobert Mustacchi }
441*fd71220bSRobert Mustacchi 
442*fd71220bSRobert Mustacchi static void
gpioadm_gpio_list_usage(FILE * f)443*fd71220bSRobert Mustacchi gpioadm_gpio_list_usage(FILE *f)
444*fd71220bSRobert Mustacchi {
445*fd71220bSRobert Mustacchi 	(void) fprintf(f, "\tgpioadm gpio list [-H] [-o field[,...] [-p]] "
446*fd71220bSRobert Mustacchi 	    "[-1] [filter...]\n");
447*fd71220bSRobert Mustacchi }
448*fd71220bSRobert Mustacchi 
449*fd71220bSRobert Mustacchi static void __PRINTFLIKE(1)
gpioadm_gpio_list_help(const char * fmt,...)450*fd71220bSRobert Mustacchi gpioadm_gpio_list_help(const char *fmt, ...)
451*fd71220bSRobert Mustacchi {
452*fd71220bSRobert Mustacchi 	if (fmt != NULL) {
453*fd71220bSRobert Mustacchi 		va_list ap;
454*fd71220bSRobert Mustacchi 
455*fd71220bSRobert Mustacchi 		va_start(ap, fmt);
456*fd71220bSRobert Mustacchi 		vwarnx(fmt, ap);
457*fd71220bSRobert Mustacchi 		va_end(ap);
458*fd71220bSRobert Mustacchi 	}
459*fd71220bSRobert Mustacchi 
460*fd71220bSRobert Mustacchi 	(void) fprintf(stderr, "Usage:  gpioadm gpio list [-H] [-o "
461*fd71220bSRobert Mustacchi 	    "field[,...] [-p]] [-1] [filter...]\n");
462*fd71220bSRobert Mustacchi 	(void) fprintf(stderr, "\nList GPIOs in the system.\n\n"
463*fd71220bSRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
464*fd71220bSRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
465*fd71220bSRobert Mustacchi 	    "\t-p\t\tparsable output (requires -o)\n"
466*fd71220bSRobert Mustacchi 	    "\t-1\t\terror if more than one GPIO is listed\n\n"
467*fd71220bSRobert Mustacchi 	    "The following fields are supported:\n"
468*fd71220bSRobert Mustacchi 	    "\tcontroller\tthe name of the controller\n"
469*fd71220bSRobert Mustacchi 	    "\tgpio\t\tthe name of the gpio\n"
470*fd71220bSRobert Mustacchi 	    "\tid\t\tthe GPIO's numeric id\n"
471*fd71220bSRobert Mustacchi 	    "Filters can be used to constrain the GPIOs that are listed. If a "
472*fd71220bSRobert Mustacchi 	    "filter is\npresent, it will be an error if it is unused. Filters "
473*fd71220bSRobert Mustacchi 	    "can specify either an\nentire controller, a specific GPIO on a "
474*fd71220bSRobert Mustacchi 	    "controller, or all GPIOs with a given\nname. The controller and "
475*fd71220bSRobert Mustacchi 	    "GPIO are separated with a '/' character. For example:\n\n"
476*fd71220bSRobert Mustacchi 	    "\tgpio_sim0\t\tThis would match all GPIOs on the controller\n"
477*fd71220bSRobert Mustacchi 	    "\t\t\t\t'gpio_sim0'.\n"
478*fd71220bSRobert Mustacchi 	    "\tzen_gpio0/EGPIO9_3\tThis would match the specific GPIO, "
479*fd71220bSRobert Mustacchi 	    "EGPIO9_3,\n\t\t\t\ton the specified controller, zen_gpio0.\n"
480*fd71220bSRobert Mustacchi 	    "\t*/gpio3\t\t\tThis would match all GPIOs named 'gpio3' on any\n"
481*fd71220bSRobert Mustacchi 	    "\t\t\t\tcontroller.\n");
482*fd71220bSRobert Mustacchi }
483*fd71220bSRobert Mustacchi 
484*fd71220bSRobert Mustacchi typedef enum gpioadm_gpio_list_otype {
485*fd71220bSRobert Mustacchi 	GPIOADM_GPIO_LIST_CTRL,
486*fd71220bSRobert Mustacchi 	GPIOADM_GPIO_LIST_NAME,
487*fd71220bSRobert Mustacchi 	GPIOADM_GPIO_LIST_ID
488*fd71220bSRobert Mustacchi } gpioadm_gpio_list_otype_t;
489*fd71220bSRobert Mustacchi 
490*fd71220bSRobert Mustacchi typedef struct gpioadm_gpio_list_ofmt {
491*fd71220bSRobert Mustacchi 	const char *gglo_minor;
492*fd71220bSRobert Mustacchi 	const char *gglo_name;
493*fd71220bSRobert Mustacchi 	uint32_t gglo_id;
494*fd71220bSRobert Mustacchi 	uint32_t gglo_flags;
495*fd71220bSRobert Mustacchi } gpioadm_gpio_list_ofmt_t;
496*fd71220bSRobert Mustacchi 
497*fd71220bSRobert Mustacchi static boolean_t
gpioadm_gpio_list_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)498*fd71220bSRobert Mustacchi gpioadm_gpio_list_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
499*fd71220bSRobert Mustacchi {
500*fd71220bSRobert Mustacchi 	gpioadm_gpio_list_ofmt_t *gglo = ofarg->ofmt_cbarg;
501*fd71220bSRobert Mustacchi 
502*fd71220bSRobert Mustacchi 	switch (ofarg->ofmt_id) {
503*fd71220bSRobert Mustacchi 	case GPIOADM_GPIO_LIST_CTRL:
504*fd71220bSRobert Mustacchi 		if (strlcpy(buf, gglo->gglo_minor, buflen) >= buflen) {
505*fd71220bSRobert Mustacchi 			return (B_FALSE);
506*fd71220bSRobert Mustacchi 		}
507*fd71220bSRobert Mustacchi 		break;
508*fd71220bSRobert Mustacchi 	case GPIOADM_GPIO_LIST_NAME:
509*fd71220bSRobert Mustacchi 		if (strlcpy(buf, gglo->gglo_name, buflen) >= buflen) {
510*fd71220bSRobert Mustacchi 			return (B_FALSE);
511*fd71220bSRobert Mustacchi 		}
512*fd71220bSRobert Mustacchi 		break;
513*fd71220bSRobert Mustacchi 	case GPIOADM_GPIO_LIST_ID:
514*fd71220bSRobert Mustacchi 		if (snprintf(buf, buflen, "%u", gglo->gglo_id) >= buflen) {
515*fd71220bSRobert Mustacchi 			return (B_FALSE);
516*fd71220bSRobert Mustacchi 		}
517*fd71220bSRobert Mustacchi 		break;
518*fd71220bSRobert Mustacchi 	default:
519*fd71220bSRobert Mustacchi 		abort();
520*fd71220bSRobert Mustacchi 	}
521*fd71220bSRobert Mustacchi 	return (B_TRUE);
522*fd71220bSRobert Mustacchi }
523*fd71220bSRobert Mustacchi 
524*fd71220bSRobert Mustacchi static const char *gpioadm_gpio_list_fields = "controller,gpio,id";
525*fd71220bSRobert Mustacchi static const ofmt_field_t gpioadm_gpio_list_ofmt[] = {
526*fd71220bSRobert Mustacchi 	{ "CONTROLLER", 16, GPIOADM_GPIO_LIST_CTRL,
527*fd71220bSRobert Mustacchi 	    gpioadm_gpio_list_ofmt_cb },
528*fd71220bSRobert Mustacchi 	{ "GPIO", 20, GPIOADM_GPIO_LIST_NAME,
529*fd71220bSRobert Mustacchi 	    gpioadm_gpio_list_ofmt_cb },
530*fd71220bSRobert Mustacchi 	{ "ID", 8, GPIOADM_GPIO_LIST_ID,
531*fd71220bSRobert Mustacchi 	    gpioadm_gpio_list_ofmt_cb },
532*fd71220bSRobert Mustacchi 	{ NULL, 0, 0, NULL }
533*fd71220bSRobert Mustacchi };
534*fd71220bSRobert Mustacchi 
535*fd71220bSRobert Mustacchi typedef struct {
536*fd71220bSRobert Mustacchi 	bool ggl_err;
537*fd71220bSRobert Mustacchi 	bool ggl_one;
538*fd71220bSRobert Mustacchi 	uint_t ggl_nprint;
539*fd71220bSRobert Mustacchi 	ofmt_handle_t ggl_ofmt;
540*fd71220bSRobert Mustacchi 	int ggl_nfilts;
541*fd71220bSRobert Mustacchi 	char *const *ggl_filts;
542*fd71220bSRobert Mustacchi 	bool *ggl_used;
543*fd71220bSRobert Mustacchi } gpioadm_gpio_list_t;
544*fd71220bSRobert Mustacchi 
545*fd71220bSRobert Mustacchi static bool
gpioadm_gpio_list_match(const char * ctrl,const char * gpio,gpioadm_gpio_list_t * ggl)546*fd71220bSRobert Mustacchi gpioadm_gpio_list_match(const char *ctrl, const char *gpio,
547*fd71220bSRobert Mustacchi     gpioadm_gpio_list_t *ggl)
548*fd71220bSRobert Mustacchi {
549*fd71220bSRobert Mustacchi 	if (ggl->ggl_nfilts <= 0) {
550*fd71220bSRobert Mustacchi 		return (true);
551*fd71220bSRobert Mustacchi 	}
552*fd71220bSRobert Mustacchi 
553*fd71220bSRobert Mustacchi 	for (int i = 0; i < ggl->ggl_nfilts; i++) {
554*fd71220bSRobert Mustacchi 		const char *filt = ggl->ggl_filts[i];
555*fd71220bSRobert Mustacchi 		const char *slash = strchr(filt, '/');
556*fd71220bSRobert Mustacchi 		bool all_ctrls;
557*fd71220bSRobert Mustacchi 		size_t ctrl_len;
558*fd71220bSRobert Mustacchi 
559*fd71220bSRobert Mustacchi 		/*
560*fd71220bSRobert Mustacchi 		 * This is just a controller filter.
561*fd71220bSRobert Mustacchi 		 */
562*fd71220bSRobert Mustacchi 		if (slash == NULL) {
563*fd71220bSRobert Mustacchi 			if (strcmp(ctrl, filt) == 0) {
564*fd71220bSRobert Mustacchi 				ggl->ggl_used[i] = true;
565*fd71220bSRobert Mustacchi 				return (true);
566*fd71220bSRobert Mustacchi 			}
567*fd71220bSRobert Mustacchi 		}
568*fd71220bSRobert Mustacchi 
569*fd71220bSRobert Mustacchi 		ctrl_len = (uintptr_t)slash - (uintptr_t)filt;
570*fd71220bSRobert Mustacchi 		if (ctrl_len == 0) {
571*fd71220bSRobert Mustacchi 			return (false);
572*fd71220bSRobert Mustacchi 		}
573*fd71220bSRobert Mustacchi 
574*fd71220bSRobert Mustacchi 		all_ctrls = ctrl_len == 1 && filt[0] == '*';
575*fd71220bSRobert Mustacchi 		if (!all_ctrls && (strlen(ctrl) != ctrl_len ||
576*fd71220bSRobert Mustacchi 		    strncmp(ctrl, filt, ctrl_len) != 0)) {
577*fd71220bSRobert Mustacchi 			continue;
578*fd71220bSRobert Mustacchi 		}
579*fd71220bSRobert Mustacchi 
580*fd71220bSRobert Mustacchi 		if (strcmp(slash + 1, gpio) == 0) {
581*fd71220bSRobert Mustacchi 			ggl->ggl_used[i] = true;
582*fd71220bSRobert Mustacchi 			return (true);
583*fd71220bSRobert Mustacchi 		}
584*fd71220bSRobert Mustacchi 	}
585*fd71220bSRobert Mustacchi 
586*fd71220bSRobert Mustacchi 	return (false);
587*fd71220bSRobert Mustacchi }
588*fd71220bSRobert Mustacchi 
589*fd71220bSRobert Mustacchi static bool
gpioadm_gpio_list_cb(xpio_t * xpio,xpio_ctrl_disc_t * disc,void * arg)590*fd71220bSRobert Mustacchi gpioadm_gpio_list_cb(xpio_t *xpio, xpio_ctrl_disc_t *disc, void *arg)
591*fd71220bSRobert Mustacchi {
592*fd71220bSRobert Mustacchi 	xpio_ctrl_t *ctrl;
593*fd71220bSRobert Mustacchi 	xpio_ctrl_info_t *info;
594*fd71220bSRobert Mustacchi 	uint32_t ngpios;
595*fd71220bSRobert Mustacchi 	const char *mname = di_minor_name(disc->xcd_minor);
596*fd71220bSRobert Mustacchi 	gpioadm_gpio_list_t *ggl = arg;
597*fd71220bSRobert Mustacchi 
598*fd71220bSRobert Mustacchi 	if (!xpio_ctrl_init(xpio, disc->xcd_minor, &ctrl)) {
599*fd71220bSRobert Mustacchi 		gpioadm_warn("failed to initialize controller %s", mname);
600*fd71220bSRobert Mustacchi 		ggl->ggl_err = true;
601*fd71220bSRobert Mustacchi 		return (true);
602*fd71220bSRobert Mustacchi 	}
603*fd71220bSRobert Mustacchi 
604*fd71220bSRobert Mustacchi 	if (!xpio_ctrl_info(ctrl, &info)) {
605*fd71220bSRobert Mustacchi 		gpioadm_warn("failed to get controller info for %s", mname);
606*fd71220bSRobert Mustacchi 		xpio_ctrl_fini(ctrl);
607*fd71220bSRobert Mustacchi 		ggl->ggl_err = true;
608*fd71220bSRobert Mustacchi 		return (true);
609*fd71220bSRobert Mustacchi 	}
610*fd71220bSRobert Mustacchi 
611*fd71220bSRobert Mustacchi 	ngpios = xpio_ctrl_info_ngpios(info);
612*fd71220bSRobert Mustacchi 	for (uint32_t i = 0; i < ngpios; i++) {
613*fd71220bSRobert Mustacchi 		gpioadm_gpio_list_ofmt_t list;
614*fd71220bSRobert Mustacchi 		xpio_gpio_info_t *gpio_info;
615*fd71220bSRobert Mustacchi 		xpio_gpio_attr_t *attr;
616*fd71220bSRobert Mustacchi 
617*fd71220bSRobert Mustacchi 		if (!xpio_gpio_info(ctrl, i, &gpio_info)) {
618*fd71220bSRobert Mustacchi 			ggl->ggl_err = true;
619*fd71220bSRobert Mustacchi 			gpioadm_warn("failed to get gpio info for %s:%u",
620*fd71220bSRobert Mustacchi 			    mname, i);
621*fd71220bSRobert Mustacchi 			continue;
622*fd71220bSRobert Mustacchi 		}
623*fd71220bSRobert Mustacchi 
624*fd71220bSRobert Mustacchi 		attr = xpio_gpio_attr_find(gpio_info, KGPIO_ATTR_NAME);
625*fd71220bSRobert Mustacchi 		if (attr == NULL || !xpio_gpio_attr_value_string(attr,
626*fd71220bSRobert Mustacchi 		    &list.gglo_name)) {
627*fd71220bSRobert Mustacchi 			warnx("GPIO %s/%u missing name attribute",
628*fd71220bSRobert Mustacchi 			    mname, i);
629*fd71220bSRobert Mustacchi 			goto skip;
630*fd71220bSRobert Mustacchi 		}
631*fd71220bSRobert Mustacchi 		list.gglo_minor = mname;
632*fd71220bSRobert Mustacchi 		list.gglo_id = i;
633*fd71220bSRobert Mustacchi 		list.gglo_flags = 0;
634*fd71220bSRobert Mustacchi 
635*fd71220bSRobert Mustacchi 		if (!gpioadm_gpio_list_match(mname, list.gglo_name, ggl)) {
636*fd71220bSRobert Mustacchi 			goto skip;
637*fd71220bSRobert Mustacchi 		}
638*fd71220bSRobert Mustacchi 
639*fd71220bSRobert Mustacchi 		ggl->ggl_nprint++;
640*fd71220bSRobert Mustacchi 		ofmt_print(ggl->ggl_ofmt, &list);
641*fd71220bSRobert Mustacchi 
642*fd71220bSRobert Mustacchi skip:
643*fd71220bSRobert Mustacchi 		xpio_gpio_info_free(gpio_info);
644*fd71220bSRobert Mustacchi 	}
645*fd71220bSRobert Mustacchi 
646*fd71220bSRobert Mustacchi 	xpio_ctrl_fini(ctrl);
647*fd71220bSRobert Mustacchi 	return (true);
648*fd71220bSRobert Mustacchi }
649*fd71220bSRobert Mustacchi 
650*fd71220bSRobert Mustacchi static int
gpioadm_gpio_list(int argc,char * argv[])651*fd71220bSRobert Mustacchi gpioadm_gpio_list(int argc, char *argv[])
652*fd71220bSRobert Mustacchi {
653*fd71220bSRobert Mustacchi 	int c;
654*fd71220bSRobert Mustacchi 	uint_t flags = 0;
655*fd71220bSRobert Mustacchi 	boolean_t parse = B_FALSE;
656*fd71220bSRobert Mustacchi 	const char *fields = NULL;
657*fd71220bSRobert Mustacchi 	ofmt_status_t oferr;
658*fd71220bSRobert Mustacchi 	ofmt_handle_t ofmt;
659*fd71220bSRobert Mustacchi 	gpioadm_gpio_list_t ggl;
660*fd71220bSRobert Mustacchi 
661*fd71220bSRobert Mustacchi 	(void) memset(&ggl, 0, sizeof (ggl));
662*fd71220bSRobert Mustacchi 	while ((c = getopt(argc, argv, ":Ho:p1")) != -1) {
663*fd71220bSRobert Mustacchi 		switch (c) {
664*fd71220bSRobert Mustacchi 		case 'H':
665*fd71220bSRobert Mustacchi 			flags |= OFMT_NOHEADER;
666*fd71220bSRobert Mustacchi 			break;
667*fd71220bSRobert Mustacchi 		case 'o':
668*fd71220bSRobert Mustacchi 			fields = optarg;
669*fd71220bSRobert Mustacchi 			break;
670*fd71220bSRobert Mustacchi 		case 'p':
671*fd71220bSRobert Mustacchi 			parse = B_TRUE;
672*fd71220bSRobert Mustacchi 			flags |= OFMT_PARSABLE;
673*fd71220bSRobert Mustacchi 			break;
674*fd71220bSRobert Mustacchi 		case '1':
675*fd71220bSRobert Mustacchi 			ggl.ggl_one = true;
676*fd71220bSRobert Mustacchi 			break;
677*fd71220bSRobert Mustacchi 		case ':':
678*fd71220bSRobert Mustacchi 			gpioadm_gpio_list_help("option -%c requires an "
679*fd71220bSRobert Mustacchi 			    "argument", optopt);
680*fd71220bSRobert Mustacchi 			exit(EXIT_USAGE);
681*fd71220bSRobert Mustacchi 		case '?':
682*fd71220bSRobert Mustacchi 			gpioadm_gpio_list_help("unknown option: -%c", optopt);
683*fd71220bSRobert Mustacchi 			exit(EXIT_USAGE);
684*fd71220bSRobert Mustacchi 		}
685*fd71220bSRobert Mustacchi 	}
686*fd71220bSRobert Mustacchi 
687*fd71220bSRobert Mustacchi 	if (parse && fields == NULL) {
688*fd71220bSRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
689*fd71220bSRobert Mustacchi 	}
690*fd71220bSRobert Mustacchi 
691*fd71220bSRobert Mustacchi 	if (fields == NULL) {
692*fd71220bSRobert Mustacchi 		fields = gpioadm_gpio_list_fields;
693*fd71220bSRobert Mustacchi 	}
694*fd71220bSRobert Mustacchi 
695*fd71220bSRobert Mustacchi 	argc -= optind;
696*fd71220bSRobert Mustacchi 	argv += optind;
697*fd71220bSRobert Mustacchi 	if (argc > 0) {
698*fd71220bSRobert Mustacchi 		ggl.ggl_nfilts = argc;
699*fd71220bSRobert Mustacchi 		ggl.ggl_filts = argv;
700*fd71220bSRobert Mustacchi 		ggl.ggl_used = calloc(argc, sizeof (bool));
701*fd71220bSRobert Mustacchi 		if (ggl.ggl_used == NULL) {
702*fd71220bSRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
703*fd71220bSRobert Mustacchi 			    "filter tracking");
704*fd71220bSRobert Mustacchi 		}
705*fd71220bSRobert Mustacchi 	}
706*fd71220bSRobert Mustacchi 	oferr = ofmt_open(fields, gpioadm_gpio_list_ofmt, flags, 0, &ofmt);
707*fd71220bSRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, gpioadm_ofmt_errx, warnx);
708*fd71220bSRobert Mustacchi 
709*fd71220bSRobert Mustacchi 	ggl.ggl_err = false;
710*fd71220bSRobert Mustacchi 	ggl.ggl_ofmt = ofmt;
711*fd71220bSRobert Mustacchi 	xpio_ctrl_discover(gpioadm.gpio_xpio, gpioadm_gpio_list_cb, &ggl);
712*fd71220bSRobert Mustacchi 
713*fd71220bSRobert Mustacchi 	for (int i = 0; i < ggl.ggl_nfilts; i++) {
714*fd71220bSRobert Mustacchi 		if (!ggl.ggl_used[i]) {
715*fd71220bSRobert Mustacchi 			warnx("filter '%s' did not match any GPIOs",
716*fd71220bSRobert Mustacchi 			    ggl.ggl_filts[i]);
717*fd71220bSRobert Mustacchi 			ggl.ggl_err = true;
718*fd71220bSRobert Mustacchi 		}
719*fd71220bSRobert Mustacchi 	}
720*fd71220bSRobert Mustacchi 
721*fd71220bSRobert Mustacchi 	if (ggl.ggl_one && ggl.ggl_nprint > 1) {
722*fd71220bSRobert Mustacchi 		warnx("-1 specified, but %u GPIOs printed", ggl.ggl_nprint);
723*fd71220bSRobert Mustacchi 		ggl.ggl_err = true;
724*fd71220bSRobert Mustacchi 	}
725*fd71220bSRobert Mustacchi 
726*fd71220bSRobert Mustacchi 	if (ggl.ggl_nprint == 0) {
727*fd71220bSRobert Mustacchi 		if (ggl.ggl_nfilts == 0) {
728*fd71220bSRobert Mustacchi 			warnx("no GPIOs found");
729*fd71220bSRobert Mustacchi 		}
730*fd71220bSRobert Mustacchi 		ggl.ggl_err = true;
731*fd71220bSRobert Mustacchi 	}
732*fd71220bSRobert Mustacchi 
733*fd71220bSRobert Mustacchi 	return (ggl.ggl_err ? EXIT_FAILURE : EXIT_SUCCESS);
734*fd71220bSRobert Mustacchi }
735*fd71220bSRobert Mustacchi 
736*fd71220bSRobert Mustacchi static const gpioadm_cmdtab_t gpioadm_cmds_gpio[] = {
737*fd71220bSRobert Mustacchi 	{ "attr", gpioadm_gpio_attr, gpioadm_gpio_attr_usage },
738*fd71220bSRobert Mustacchi 	{ "list", gpioadm_gpio_list, gpioadm_gpio_list_usage },
739*fd71220bSRobert Mustacchi 	{ NULL, NULL, NULL }
740*fd71220bSRobert Mustacchi };
741*fd71220bSRobert Mustacchi 
742*fd71220bSRobert Mustacchi int
gpioadm_gpio(int argc,char * argv[])743*fd71220bSRobert Mustacchi gpioadm_gpio(int argc, char *argv[])
744*fd71220bSRobert Mustacchi {
745*fd71220bSRobert Mustacchi 	return (gpioadm_walk_tab(gpioadm_cmds_gpio, argc, argv));
746*fd71220bSRobert Mustacchi }
747*fd71220bSRobert Mustacchi 
748*fd71220bSRobert Mustacchi void
gpioadm_gpio_usage(FILE * f)749*fd71220bSRobert Mustacchi gpioadm_gpio_usage(FILE *f)
750*fd71220bSRobert Mustacchi {
751*fd71220bSRobert Mustacchi 	gpioadm_walk_usage(gpioadm_cmds_gpio, f);
752*fd71220bSRobert Mustacchi }
753