xref: /illumos-gate/usr/src/cmd/gpioadm/gpioadm_controller.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_controller_list_usage(FILE * f)28*fd71220bSRobert Mustacchi gpioadm_controller_list_usage(FILE *f)
29*fd71220bSRobert Mustacchi {
30*fd71220bSRobert Mustacchi 	(void) fprintf(f, "\tgpioadm controller list [-H] [-o field[,...] "
31*fd71220bSRobert Mustacchi 	    "[-p]] [filter...]\n");
32*fd71220bSRobert Mustacchi }
33*fd71220bSRobert Mustacchi 
34*fd71220bSRobert Mustacchi static void __PRINTFLIKE(1)
gpioadm_controller_list_help(const char * fmt,...)35*fd71220bSRobert Mustacchi gpioadm_controller_list_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 controller list [-H] [-o "
46*fd71220bSRobert Mustacchi 	    "field[,...] [-p]] [filter...]\n");
47*fd71220bSRobert Mustacchi 	(void) fprintf(stderr, "\nList GPIO controllers in the system and "
48*fd71220bSRobert Mustacchi 	    "associated information.\n\n"
49*fd71220bSRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
50*fd71220bSRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
51*fd71220bSRobert Mustacchi 	    "\t-p\t\tparsable output (requires -o)\n\n"
52*fd71220bSRobert Mustacchi 	    "The following fields are supported:\n"
53*fd71220bSRobert Mustacchi 	    "\tcontroller\tthe name of the controller\n"
54*fd71220bSRobert Mustacchi 	    "\tngpios\t\tthe number of GPIOs the controller has\n"
55*fd71220bSRobert Mustacchi 	    "\tndpios\t\tthe number of DPIOs the controller has\n"
56*fd71220bSRobert Mustacchi 	    "\tpath\t\tthe path to the minor node of the controller\n"
57*fd71220bSRobert Mustacchi 	    "\tprovider\tthe /devices path of the provider\n\n"
58*fd71220bSRobert Mustacchi 	    "Filters restrict output to the named controllers. Each filter is "
59*fd71220bSRobert Mustacchi 	    "treated\nlike an OR allowing one to limit output to specific "
60*fd71220bSRobert Mustacchi 	    "controllers. It is\nan error if a controller isn't found.\n");
61*fd71220bSRobert Mustacchi }
62*fd71220bSRobert Mustacchi 
63*fd71220bSRobert Mustacchi typedef enum gpioadm_controller_list_otype {
64*fd71220bSRobert Mustacchi 	GPIOADM_CTRL_LIST_CTRLR,
65*fd71220bSRobert Mustacchi 	GPIOADM_CTRL_LIST_NGPIO,
66*fd71220bSRobert Mustacchi 	GPIOADM_CTRL_LIST_NDPIO,
67*fd71220bSRobert Mustacchi 	GPIOADM_CTRL_LIST_PATH,
68*fd71220bSRobert Mustacchi 	GPIOADM_CTRL_LIST_PROVIDER
69*fd71220bSRobert Mustacchi } gpioadm_controllier_list_otype_t;
70*fd71220bSRobert Mustacchi 
71*fd71220bSRobert Mustacchi typedef struct gpioadm_controller_list_ofmt {
72*fd71220bSRobert Mustacchi 	const char *gclo_minor;
73*fd71220bSRobert Mustacchi 	const char *gclo_devpath;
74*fd71220bSRobert Mustacchi 	char *gclo_path;
75*fd71220bSRobert Mustacchi 	uint32_t gclo_ngpio;
76*fd71220bSRobert Mustacchi 	uint32_t gclo_ndpio;
77*fd71220bSRobert Mustacchi } gpioadm_controller_list_ofmt_t;
78*fd71220bSRobert Mustacchi 
79*fd71220bSRobert Mustacchi static boolean_t
gpioadm_controller_list_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)80*fd71220bSRobert Mustacchi gpioadm_controller_list_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
81*fd71220bSRobert Mustacchi {
82*fd71220bSRobert Mustacchi 	gpioadm_controller_list_ofmt_t *gclo = ofarg->ofmt_cbarg;
83*fd71220bSRobert Mustacchi 
84*fd71220bSRobert Mustacchi 	switch (ofarg->ofmt_id) {
85*fd71220bSRobert Mustacchi 	case GPIOADM_CTRL_LIST_CTRLR:
86*fd71220bSRobert Mustacchi 		if (strlcpy(buf, gclo->gclo_minor, buflen) >= buflen) {
87*fd71220bSRobert Mustacchi 			return (B_FALSE);
88*fd71220bSRobert Mustacchi 		}
89*fd71220bSRobert Mustacchi 		break;
90*fd71220bSRobert Mustacchi 	case GPIOADM_CTRL_LIST_NGPIO:
91*fd71220bSRobert Mustacchi 		if (snprintf(buf, buflen, "%u", gclo->gclo_ngpio) >= buflen) {
92*fd71220bSRobert Mustacchi 			return (B_FALSE);
93*fd71220bSRobert Mustacchi 		}
94*fd71220bSRobert Mustacchi 		break;
95*fd71220bSRobert Mustacchi 	case GPIOADM_CTRL_LIST_NDPIO:
96*fd71220bSRobert Mustacchi 		if (snprintf(buf, buflen, "%u", gclo->gclo_ndpio) >= buflen) {
97*fd71220bSRobert Mustacchi 			return (B_FALSE);
98*fd71220bSRobert Mustacchi 		}
99*fd71220bSRobert Mustacchi 		break;
100*fd71220bSRobert Mustacchi 	case GPIOADM_CTRL_LIST_PROVIDER:
101*fd71220bSRobert Mustacchi 		if (strlcpy(buf, gclo->gclo_devpath, buflen) >= buflen) {
102*fd71220bSRobert Mustacchi 			return (B_FALSE);
103*fd71220bSRobert Mustacchi 		}
104*fd71220bSRobert Mustacchi 		break;
105*fd71220bSRobert Mustacchi 	case GPIOADM_CTRL_LIST_PATH:
106*fd71220bSRobert Mustacchi 		/*
107*fd71220bSRobert Mustacchi 		 * Asking for the minor path can fail. So if we have nothing,
108*fd71220bSRobert Mustacchi 		 * just ignore this.
109*fd71220bSRobert Mustacchi 		 */
110*fd71220bSRobert Mustacchi 		if (gclo->gclo_path == NULL)
111*fd71220bSRobert Mustacchi 			break;
112*fd71220bSRobert Mustacchi 		if (strlcpy(buf, gclo->gclo_path, buflen) >= buflen) {
113*fd71220bSRobert Mustacchi 			return (B_FALSE);
114*fd71220bSRobert Mustacchi 		}
115*fd71220bSRobert Mustacchi 		break;
116*fd71220bSRobert Mustacchi 	default:
117*fd71220bSRobert Mustacchi 		abort();
118*fd71220bSRobert Mustacchi 	}
119*fd71220bSRobert Mustacchi 	return (B_TRUE);
120*fd71220bSRobert Mustacchi }
121*fd71220bSRobert Mustacchi 
122*fd71220bSRobert Mustacchi static const char *gpioadm_controller_list_fields = "controller,ngpios,ndpios,"
123*fd71220bSRobert Mustacchi 	"provider";
124*fd71220bSRobert Mustacchi static const ofmt_field_t gpioadm_controller_list_ofmt[] = {
125*fd71220bSRobert Mustacchi 	{ "CONTROLLER", 16, GPIOADM_CTRL_LIST_CTRLR,
126*fd71220bSRobert Mustacchi 	    gpioadm_controller_list_ofmt_cb },
127*fd71220bSRobert Mustacchi 	{ "NGPIOS", 8, GPIOADM_CTRL_LIST_NGPIO,
128*fd71220bSRobert Mustacchi 	    gpioadm_controller_list_ofmt_cb },
129*fd71220bSRobert Mustacchi 	{ "NDPIOS", 8, GPIOADM_CTRL_LIST_NDPIO,
130*fd71220bSRobert Mustacchi 	    gpioadm_controller_list_ofmt_cb },
131*fd71220bSRobert Mustacchi 	{ "PROVIDER", 42, GPIOADM_CTRL_LIST_PROVIDER,
132*fd71220bSRobert Mustacchi 	    gpioadm_controller_list_ofmt_cb },
133*fd71220bSRobert Mustacchi 	{ "PATH", 42, GPIOADM_CTRL_LIST_PATH,
134*fd71220bSRobert Mustacchi 	    gpioadm_controller_list_ofmt_cb },
135*fd71220bSRobert Mustacchi 	{ NULL, 0, 0, NULL }
136*fd71220bSRobert Mustacchi };
137*fd71220bSRobert Mustacchi 
138*fd71220bSRobert Mustacchi typedef struct {
139*fd71220bSRobert Mustacchi 	ofmt_handle_t gcl_ofmt;
140*fd71220bSRobert Mustacchi 	uint32_t gcl_nprint;
141*fd71220bSRobert Mustacchi 	bool gcl_err;
142*fd71220bSRobert Mustacchi 	int gcl_nfilts;
143*fd71220bSRobert Mustacchi 	char **gcl_filts;
144*fd71220bSRobert Mustacchi 	bool *gcl_used;
145*fd71220bSRobert Mustacchi } gpioadm_controller_list_t;
146*fd71220bSRobert Mustacchi 
147*fd71220bSRobert Mustacchi static bool
gpioadm_controller_list_cb(xpio_t * xpio,xpio_ctrl_disc_t * disc,void * arg)148*fd71220bSRobert Mustacchi gpioadm_controller_list_cb(xpio_t *xpio, xpio_ctrl_disc_t *disc, void *arg)
149*fd71220bSRobert Mustacchi {
150*fd71220bSRobert Mustacchi 	xpio_ctrl_t *ctrl;
151*fd71220bSRobert Mustacchi 	xpio_ctrl_info_t *info;
152*fd71220bSRobert Mustacchi 	gpioadm_controller_list_ofmt_t list;
153*fd71220bSRobert Mustacchi 	gpioadm_controller_list_t *gcl = arg;
154*fd71220bSRobert Mustacchi 	const char *mname = di_minor_name(disc->xcd_minor);
155*fd71220bSRobert Mustacchi 
156*fd71220bSRobert Mustacchi 	if (gcl->gcl_nfilts > 0) {
157*fd71220bSRobert Mustacchi 		bool match = false;
158*fd71220bSRobert Mustacchi 
159*fd71220bSRobert Mustacchi 		for (int i = 0; i < gcl->gcl_nfilts; i++) {
160*fd71220bSRobert Mustacchi 			if (strcmp(mname, gcl->gcl_filts[i]) == 0) {
161*fd71220bSRobert Mustacchi 				gcl->gcl_used[i] = true;
162*fd71220bSRobert Mustacchi 				match = true;
163*fd71220bSRobert Mustacchi 				break;
164*fd71220bSRobert Mustacchi 			}
165*fd71220bSRobert Mustacchi 		}
166*fd71220bSRobert Mustacchi 
167*fd71220bSRobert Mustacchi 		if (!match) {
168*fd71220bSRobert Mustacchi 			return (true);
169*fd71220bSRobert Mustacchi 		}
170*fd71220bSRobert Mustacchi 	}
171*fd71220bSRobert Mustacchi 
172*fd71220bSRobert Mustacchi 	if (!xpio_ctrl_init(xpio, disc->xcd_minor, &ctrl)) {
173*fd71220bSRobert Mustacchi 		gpioadm_warn("failed to initialize controller %s", mname);
174*fd71220bSRobert Mustacchi 		gcl->gcl_err = B_TRUE;
175*fd71220bSRobert Mustacchi 		return (true);
176*fd71220bSRobert Mustacchi 	}
177*fd71220bSRobert Mustacchi 
178*fd71220bSRobert Mustacchi 	if (!xpio_ctrl_info(ctrl, &info)) {
179*fd71220bSRobert Mustacchi 		gpioadm_warn("failed to get controller info for %s", mname);
180*fd71220bSRobert Mustacchi 		xpio_ctrl_fini(ctrl);
181*fd71220bSRobert Mustacchi 		gcl->gcl_err = B_TRUE;
182*fd71220bSRobert Mustacchi 		return (true);
183*fd71220bSRobert Mustacchi 	}
184*fd71220bSRobert Mustacchi 
185*fd71220bSRobert Mustacchi 	bzero(&list, sizeof (list));
186*fd71220bSRobert Mustacchi 	list.gclo_minor = mname;
187*fd71220bSRobert Mustacchi 	list.gclo_ngpio = xpio_ctrl_info_ngpios(info);
188*fd71220bSRobert Mustacchi 	list.gclo_ndpio = xpio_ctrl_info_ndpios(info);
189*fd71220bSRobert Mustacchi 	list.gclo_devpath = xpio_ctrl_info_devpath(info);
190*fd71220bSRobert Mustacchi 	list.gclo_path = di_devfs_minor_path(disc->xcd_minor);
191*fd71220bSRobert Mustacchi 
192*fd71220bSRobert Mustacchi 	ofmt_print(gcl->gcl_ofmt, &list);
193*fd71220bSRobert Mustacchi 	gcl->gcl_nprint++;
194*fd71220bSRobert Mustacchi 
195*fd71220bSRobert Mustacchi 	di_devfs_path_free(list.gclo_path);
196*fd71220bSRobert Mustacchi 	xpio_ctrl_info_free(info);
197*fd71220bSRobert Mustacchi 	xpio_ctrl_fini(ctrl);
198*fd71220bSRobert Mustacchi 	return (true);
199*fd71220bSRobert Mustacchi }
200*fd71220bSRobert Mustacchi 
201*fd71220bSRobert Mustacchi static int
gpioadm_controller_list(int argc,char * argv[])202*fd71220bSRobert Mustacchi gpioadm_controller_list(int argc, char *argv[])
203*fd71220bSRobert Mustacchi {
204*fd71220bSRobert Mustacchi 	int c;
205*fd71220bSRobert Mustacchi 	uint_t flags = 0;
206*fd71220bSRobert Mustacchi 	boolean_t parse = B_FALSE;
207*fd71220bSRobert Mustacchi 	const char *fields = NULL;
208*fd71220bSRobert Mustacchi 	ofmt_status_t oferr;
209*fd71220bSRobert Mustacchi 	ofmt_handle_t ofmt;
210*fd71220bSRobert Mustacchi 	gpioadm_controller_list_t gcl;
211*fd71220bSRobert Mustacchi 
212*fd71220bSRobert Mustacchi 	(void) memset(&gcl, 0, sizeof (gcl));
213*fd71220bSRobert Mustacchi 
214*fd71220bSRobert Mustacchi 	while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
215*fd71220bSRobert Mustacchi 		switch (c) {
216*fd71220bSRobert Mustacchi 		case 'H':
217*fd71220bSRobert Mustacchi 			flags |= OFMT_NOHEADER;
218*fd71220bSRobert Mustacchi 			break;
219*fd71220bSRobert Mustacchi 		case 'o':
220*fd71220bSRobert Mustacchi 			fields = optarg;
221*fd71220bSRobert Mustacchi 			break;
222*fd71220bSRobert Mustacchi 		case 'p':
223*fd71220bSRobert Mustacchi 			parse = B_TRUE;
224*fd71220bSRobert Mustacchi 			flags |= OFMT_PARSABLE;
225*fd71220bSRobert Mustacchi 			break;
226*fd71220bSRobert Mustacchi 		case ':':
227*fd71220bSRobert Mustacchi 			gpioadm_controller_list_help("option -%c requires an "
228*fd71220bSRobert Mustacchi 			    "argument", optopt);
229*fd71220bSRobert Mustacchi 			exit(EXIT_USAGE);
230*fd71220bSRobert Mustacchi 		case '?':
231*fd71220bSRobert Mustacchi 			gpioadm_controller_list_help("unknown option: -%c",
232*fd71220bSRobert Mustacchi 			    optopt);
233*fd71220bSRobert Mustacchi 			exit(EXIT_USAGE);
234*fd71220bSRobert Mustacchi 		}
235*fd71220bSRobert Mustacchi 	}
236*fd71220bSRobert Mustacchi 
237*fd71220bSRobert Mustacchi 	if (parse && fields == NULL) {
238*fd71220bSRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
239*fd71220bSRobert Mustacchi 	}
240*fd71220bSRobert Mustacchi 
241*fd71220bSRobert Mustacchi 	if (fields == NULL) {
242*fd71220bSRobert Mustacchi 		fields = gpioadm_controller_list_fields;
243*fd71220bSRobert Mustacchi 	}
244*fd71220bSRobert Mustacchi 
245*fd71220bSRobert Mustacchi 	argc -= optind;
246*fd71220bSRobert Mustacchi 	argv += optind;
247*fd71220bSRobert Mustacchi 	if (argc > 0) {
248*fd71220bSRobert Mustacchi 		gcl.gcl_nfilts = argc;
249*fd71220bSRobert Mustacchi 		gcl.gcl_filts = argv;
250*fd71220bSRobert Mustacchi 		gcl.gcl_used = calloc(argc, sizeof (bool));
251*fd71220bSRobert Mustacchi 		if (gcl.gcl_used == NULL) {
252*fd71220bSRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate filter tracking "
253*fd71220bSRobert Mustacchi 			    "memory");
254*fd71220bSRobert Mustacchi 		}
255*fd71220bSRobert Mustacchi 	}
256*fd71220bSRobert Mustacchi 	oferr = ofmt_open(fields, gpioadm_controller_list_ofmt, flags, 0,
257*fd71220bSRobert Mustacchi 	    &ofmt);
258*fd71220bSRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, gpioadm_ofmt_errx, warnx);
259*fd71220bSRobert Mustacchi 
260*fd71220bSRobert Mustacchi 	gcl.gcl_nprint = 0;
261*fd71220bSRobert Mustacchi 	gcl.gcl_err = B_FALSE;
262*fd71220bSRobert Mustacchi 	gcl.gcl_ofmt = ofmt;
263*fd71220bSRobert Mustacchi 	xpio_ctrl_discover(gpioadm.gpio_xpio, gpioadm_controller_list_cb,
264*fd71220bSRobert Mustacchi 	    &gcl);
265*fd71220bSRobert Mustacchi 
266*fd71220bSRobert Mustacchi 	for (int i = 0; i < gcl.gcl_nfilts; i++) {
267*fd71220bSRobert Mustacchi 		if (!gcl.gcl_used[i]) {
268*fd71220bSRobert Mustacchi 			warnx("filter '%s' did not match any controllers",
269*fd71220bSRobert Mustacchi 			    gcl.gcl_filts[i]);
270*fd71220bSRobert Mustacchi 			gcl.gcl_err = true;
271*fd71220bSRobert Mustacchi 		}
272*fd71220bSRobert Mustacchi 	}
273*fd71220bSRobert Mustacchi 
274*fd71220bSRobert Mustacchi 	if (gcl.gcl_nprint == 0) {
275*fd71220bSRobert Mustacchi 		/*
276*fd71220bSRobert Mustacchi 		 * We only bother to warn about no controllers being found when
277*fd71220bSRobert Mustacchi 		 * there are no filters as otherwise the user would have gotten
278*fd71220bSRobert Mustacchi 		 * a message about unmatched filters just above.
279*fd71220bSRobert Mustacchi 		 */
280*fd71220bSRobert Mustacchi 		if (gcl.gcl_nfilts == 0) {
281*fd71220bSRobert Mustacchi 			warnx("no gpio controllers found");
282*fd71220bSRobert Mustacchi 		}
283*fd71220bSRobert Mustacchi 		gcl.gcl_err = true;
284*fd71220bSRobert Mustacchi 	}
285*fd71220bSRobert Mustacchi 
286*fd71220bSRobert Mustacchi 	return (gcl.gcl_err ? EXIT_FAILURE : EXIT_SUCCESS);
287*fd71220bSRobert Mustacchi }
288*fd71220bSRobert Mustacchi 
289*fd71220bSRobert Mustacchi static const gpioadm_cmdtab_t gpioadm_cmds_ctrl[] = {
290*fd71220bSRobert Mustacchi 	{ "list", gpioadm_controller_list, gpioadm_controller_list_usage },
291*fd71220bSRobert Mustacchi 	{ NULL, NULL, NULL }
292*fd71220bSRobert Mustacchi };
293*fd71220bSRobert Mustacchi 
294*fd71220bSRobert Mustacchi int
gpioadm_controller(int argc,char * argv[])295*fd71220bSRobert Mustacchi gpioadm_controller(int argc, char *argv[])
296*fd71220bSRobert Mustacchi {
297*fd71220bSRobert Mustacchi 	return (gpioadm_walk_tab(gpioadm_cmds_ctrl, argc, argv));
298*fd71220bSRobert Mustacchi }
299*fd71220bSRobert Mustacchi 
300*fd71220bSRobert Mustacchi void
gpioadm_controller_usage(FILE * f)301*fd71220bSRobert Mustacchi gpioadm_controller_usage(FILE *f)
302*fd71220bSRobert Mustacchi {
303*fd71220bSRobert Mustacchi 	gpioadm_walk_usage(gpioadm_cmds_ctrl, f);
304*fd71220bSRobert Mustacchi }
305