xref: /illumos-gate/usr/src/cmd/i2cadm/i2cadm_controller.c (revision 32002227574cf0a435dc03de622191ca53724f0a)
1*32002227SRobert Mustacchi /*
2*32002227SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*32002227SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*32002227SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*32002227SRobert Mustacchi  * 1.0 of the CDDL.
6*32002227SRobert Mustacchi  *
7*32002227SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*32002227SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*32002227SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*32002227SRobert Mustacchi  */
11*32002227SRobert Mustacchi 
12*32002227SRobert Mustacchi /*
13*32002227SRobert Mustacchi  * Copyright 2025 Oxide Computer Company
14*32002227SRobert Mustacchi  */
15*32002227SRobert Mustacchi 
16*32002227SRobert Mustacchi /*
17*32002227SRobert Mustacchi  * i2cadm controller related operations.
18*32002227SRobert Mustacchi  */
19*32002227SRobert Mustacchi 
20*32002227SRobert Mustacchi #include <stdio.h>
21*32002227SRobert Mustacchi #include <stdarg.h>
22*32002227SRobert Mustacchi #include <string.h>
23*32002227SRobert Mustacchi #include <err.h>
24*32002227SRobert Mustacchi #include <sys/sysmacros.h>
25*32002227SRobert Mustacchi #include <ofmt.h>
26*32002227SRobert Mustacchi #include <sys/ilstr.h>
27*32002227SRobert Mustacchi #include <sys/debug.h>
28*32002227SRobert Mustacchi 
29*32002227SRobert Mustacchi #include "i2cadm.h"
30*32002227SRobert Mustacchi 
31*32002227SRobert Mustacchi /*
32*32002227SRobert Mustacchi  * Various property conversion routines. These could also potentially be in
33*32002227SRobert Mustacchi  * libi2c if we find it useful for other consumers.
34*32002227SRobert Mustacchi  */
35*32002227SRobert Mustacchi typedef struct op_map {
36*32002227SRobert Mustacchi 	uint32_t om_op;
37*32002227SRobert Mustacchi 	const char *om_name;
38*32002227SRobert Mustacchi } op_map_t;
39*32002227SRobert Mustacchi 
40*32002227SRobert Mustacchi static const op_map_t speed_op_map[] = {
41*32002227SRobert Mustacchi 	{ I2C_SPEED_STD, "standard" },
42*32002227SRobert Mustacchi 	{ I2C_SPEED_FAST, "fast" },
43*32002227SRobert Mustacchi 	{ I2C_SPEED_FPLUS, "fast-plus" },
44*32002227SRobert Mustacchi 	{ I2C_SPEED_HIGH, "high" },
45*32002227SRobert Mustacchi 	{ I2C_SPEED_ULTRA, "ultra" }
46*32002227SRobert Mustacchi };
47*32002227SRobert Mustacchi 
48*32002227SRobert Mustacchi static const op_map_t type_op_map[] = {
49*32002227SRobert Mustacchi 	{ I2C_CTRL_TYPE_I2C, "i2c" },
50*32002227SRobert Mustacchi 	{ I2C_CTRL_TYPE_I3C, "i3c" },
51*32002227SRobert Mustacchi 	{ I2C_CTRL_TYPE_SMBUS, "smbus" }
52*32002227SRobert Mustacchi };
53*32002227SRobert Mustacchi 
54*32002227SRobert Mustacchi static const op_map_t smbus_op_map[] = {
55*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_QUICK_COMMAND, "quick" },
56*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_SEND_BYTE, "send-byte", },
57*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_RECV_BYTE, "recv-byte" },
58*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_WRITE_BYTE, "write-byte" },
59*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_READ_BYTE, "read-byte" },
60*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_WRITE_WORD, "write-word" },
61*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_READ_WORD, "read-word" },
62*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_PROCESS_CALL, "process-call" },
63*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_WRITE_BLOCK, "write-block" },
64*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_READ_BLOCK, "read-block" },
65*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_HOST_NOTIFY, "host-notify" },
66*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_BLOCK_PROCESS_CALL, "block-call" },
67*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_WRITE_U32, "write-u32" },
68*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_READ_U32, "read-u32" },
69*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_WRITE_U64, "write-u64" },
70*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_READ_U64, "read-u64" },
71*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_I2C_WRITE_BLOCK, "write-i2c-block" },
72*32002227SRobert Mustacchi 	{ SMBUS_PROP_OP_I2C_READ_BLOCK, "read-i2c-block" }
73*32002227SRobert Mustacchi };
74*32002227SRobert Mustacchi 
75*32002227SRobert Mustacchi static boolean_t
i2cadm_map_to_str_one(uint32_t val,char * buf,uint_t buflen,const op_map_t * map,size_t nents)76*32002227SRobert Mustacchi i2cadm_map_to_str_one(uint32_t val, char *buf, uint_t buflen,
77*32002227SRobert Mustacchi     const op_map_t *map, size_t nents)
78*32002227SRobert Mustacchi {
79*32002227SRobert Mustacchi 	if (val == 0) {
80*32002227SRobert Mustacchi 		return (strlcpy(buf, "--", buflen) < buflen);
81*32002227SRobert Mustacchi 	}
82*32002227SRobert Mustacchi 
83*32002227SRobert Mustacchi 	for (size_t i = 0; i < nents; i++) {
84*32002227SRobert Mustacchi 		if (map[i].om_op == val) {
85*32002227SRobert Mustacchi 			return (strlcpy(buf, map[i].om_name, buflen) < buflen);
86*32002227SRobert Mustacchi 		}
87*32002227SRobert Mustacchi 	}
88*32002227SRobert Mustacchi 
89*32002227SRobert Mustacchi 	return (B_FALSE);
90*32002227SRobert Mustacchi }
91*32002227SRobert Mustacchi 
92*32002227SRobert Mustacchi static boolean_t
i2cadm_map_to_str(uint32_t val,char * buf,uint_t buflen,const op_map_t * map,size_t nents)93*32002227SRobert Mustacchi i2cadm_map_to_str(uint32_t val, char *buf, uint_t buflen, const op_map_t *map,
94*32002227SRobert Mustacchi     size_t nents)
95*32002227SRobert Mustacchi {
96*32002227SRobert Mustacchi 	ilstr_t ilstr;
97*32002227SRobert Mustacchi 
98*32002227SRobert Mustacchi 	if (val == 0) {
99*32002227SRobert Mustacchi 		return (strlcpy(buf, "--", buflen) < buflen);
100*32002227SRobert Mustacchi 	}
101*32002227SRobert Mustacchi 
102*32002227SRobert Mustacchi 	ilstr_init_prealloc(&ilstr, buf, buflen);
103*32002227SRobert Mustacchi 
104*32002227SRobert Mustacchi 	for (size_t i = 0; i < nents; i++) {
105*32002227SRobert Mustacchi 		if ((val & map[i].om_op) == 0)
106*32002227SRobert Mustacchi 			continue;
107*32002227SRobert Mustacchi 
108*32002227SRobert Mustacchi 		val &= ~map[i].om_op;
109*32002227SRobert Mustacchi 		if (i > 0) {
110*32002227SRobert Mustacchi 			ilstr_append_char(&ilstr, ',');
111*32002227SRobert Mustacchi 		}
112*32002227SRobert Mustacchi 		ilstr_append_str(&ilstr, map[i].om_name);
113*32002227SRobert Mustacchi 	}
114*32002227SRobert Mustacchi 
115*32002227SRobert Mustacchi 	if (val != 0) {
116*32002227SRobert Mustacchi 		char str[32];
117*32002227SRobert Mustacchi 		(void) snprintf(str, sizeof (str), ",0x%x", val);
118*32002227SRobert Mustacchi 
119*32002227SRobert Mustacchi 		if (ilstr_len(&ilstr) > 0) {
120*32002227SRobert Mustacchi 			ilstr_append_char(&ilstr, ',');
121*32002227SRobert Mustacchi 		}
122*32002227SRobert Mustacchi 		ilstr_append_str(&ilstr, str);
123*32002227SRobert Mustacchi 	}
124*32002227SRobert Mustacchi 
125*32002227SRobert Mustacchi 	ilstr_errno_t err = ilstr_errno(&ilstr);
126*32002227SRobert Mustacchi 	ilstr_fini(&ilstr);
127*32002227SRobert Mustacchi 	return (err == ILSTR_ERROR_OK);
128*32002227SRobert Mustacchi }
129*32002227SRobert Mustacchi 
130*32002227SRobert Mustacchi static boolean_t
i2cadm_value_print(i2c_prop_info_t * info,uint32_t val,char * buf,uint_t buflen)131*32002227SRobert Mustacchi i2cadm_value_print(i2c_prop_info_t *info, uint32_t val, char *buf,
132*32002227SRobert Mustacchi     uint_t buflen)
133*32002227SRobert Mustacchi {
134*32002227SRobert Mustacchi 	uint_t len;
135*32002227SRobert Mustacchi 
136*32002227SRobert Mustacchi 	switch (i2c_prop_info_id(info)) {
137*32002227SRobert Mustacchi 	case I2C_PROP_BUS_SPEED:
138*32002227SRobert Mustacchi 		return (i2cadm_map_to_str_one(val, buf, buflen, speed_op_map,
139*32002227SRobert Mustacchi 		    ARRAY_SIZE(speed_op_map)));
140*32002227SRobert Mustacchi 	case I2C_PROP_TYPE:
141*32002227SRobert Mustacchi 		return (i2cadm_map_to_str_one(val, buf, buflen, type_op_map,
142*32002227SRobert Mustacchi 		    ARRAY_SIZE(type_op_map)));
143*32002227SRobert Mustacchi 	case SMBUS_PROP_SUP_OPS:
144*32002227SRobert Mustacchi 		return (i2cadm_map_to_str(val, buf, buflen, smbus_op_map,
145*32002227SRobert Mustacchi 		    ARRAY_SIZE(smbus_op_map)));
146*32002227SRobert Mustacchi 	default:
147*32002227SRobert Mustacchi 		len = snprintf(buf, buflen, "%u", val);
148*32002227SRobert Mustacchi 	}
149*32002227SRobert Mustacchi 
150*32002227SRobert Mustacchi 	return (len < buflen);
151*32002227SRobert Mustacchi }
152*32002227SRobert Mustacchi 
153*32002227SRobert Mustacchi static boolean_t
i2cadm_value_print_pos_u32(const i2c_prop_range_t * range,char * buf,uint_t buflen)154*32002227SRobert Mustacchi i2cadm_value_print_pos_u32(const i2c_prop_range_t *range, char *buf,
155*32002227SRobert Mustacchi     uint_t buflen)
156*32002227SRobert Mustacchi {
157*32002227SRobert Mustacchi 	ilstr_t ilstr;
158*32002227SRobert Mustacchi 
159*32002227SRobert Mustacchi 	ilstr_init_prealloc(&ilstr, buf, buflen);
160*32002227SRobert Mustacchi 	for (uint32_t i = 0; i < range->ipr_count; i++) {
161*32002227SRobert Mustacchi 		const i2c_prop_u32_range_t *r;
162*32002227SRobert Mustacchi 		char str[64];
163*32002227SRobert Mustacchi 
164*32002227SRobert Mustacchi 		r = &range->ipr_range[i].ipvr_u32;
165*32002227SRobert Mustacchi 		if (r->ipur_min == r->ipur_max) {
166*32002227SRobert Mustacchi 			(void) snprintf(str, sizeof (str), "u", r->ipur_min);
167*32002227SRobert Mustacchi 		} else {
168*32002227SRobert Mustacchi 			(void) snprintf(str, sizeof (str), "%u-%u", r->ipur_min,
169*32002227SRobert Mustacchi 			    r->ipur_max);
170*32002227SRobert Mustacchi 		}
171*32002227SRobert Mustacchi 		if (i > 0) {
172*32002227SRobert Mustacchi 			ilstr_append_char(&ilstr, ',');
173*32002227SRobert Mustacchi 		}
174*32002227SRobert Mustacchi 		ilstr_append_str(&ilstr, str);
175*32002227SRobert Mustacchi 	}
176*32002227SRobert Mustacchi 
177*32002227SRobert Mustacchi 	ilstr_errno_t err = ilstr_errno(&ilstr);
178*32002227SRobert Mustacchi 	ilstr_fini(&ilstr);
179*32002227SRobert Mustacchi 	return (err == ILSTR_ERROR_OK);
180*32002227SRobert Mustacchi }
181*32002227SRobert Mustacchi 
182*32002227SRobert Mustacchi static boolean_t
i2cadm_value_print_pos_bit32(i2c_prop_info_t * info,const i2c_prop_range_t * range,char * buf,uint_t buflen)183*32002227SRobert Mustacchi i2cadm_value_print_pos_bit32(i2c_prop_info_t *info,
184*32002227SRobert Mustacchi     const i2c_prop_range_t *range, char *buf, uint_t buflen)
185*32002227SRobert Mustacchi {
186*32002227SRobert Mustacchi 	if (range->ipr_count != 1) {
187*32002227SRobert Mustacchi 		return (B_FALSE);
188*32002227SRobert Mustacchi 	}
189*32002227SRobert Mustacchi 
190*32002227SRobert Mustacchi 	uint32_t val = range->ipr_range[0].ipvr_bit32;
191*32002227SRobert Mustacchi 	switch (i2c_prop_info_id(info)) {
192*32002227SRobert Mustacchi 	case I2C_PROP_BUS_SPEED:
193*32002227SRobert Mustacchi 		return (i2cadm_map_to_str(val, buf, buflen, speed_op_map,
194*32002227SRobert Mustacchi 		    ARRAY_SIZE(speed_op_map)));
195*32002227SRobert Mustacchi 	case SMBUS_PROP_SUP_OPS:
196*32002227SRobert Mustacchi 		return (i2cadm_map_to_str(val, buf, buflen, smbus_op_map,
197*32002227SRobert Mustacchi 		    ARRAY_SIZE(smbus_op_map)));
198*32002227SRobert Mustacchi 	default:
199*32002227SRobert Mustacchi 		return (snprintf(buf, buflen, "0x%x", val) < buflen);
200*32002227SRobert Mustacchi 	}
201*32002227SRobert Mustacchi }
202*32002227SRobert Mustacchi 
203*32002227SRobert Mustacchi static boolean_t
i2cadm_value_print_pos(i2c_prop_info_t * info,char * buf,uint_t buflen)204*32002227SRobert Mustacchi i2cadm_value_print_pos(i2c_prop_info_t *info, char *buf, uint_t buflen)
205*32002227SRobert Mustacchi {
206*32002227SRobert Mustacchi 	uint_t len;
207*32002227SRobert Mustacchi 	const i2c_prop_range_t *range = i2c_prop_info_pos(info);
208*32002227SRobert Mustacchi 
209*32002227SRobert Mustacchi 	if (range == NULL) {
210*32002227SRobert Mustacchi 		if (i2c_err(i2cadm.i2c_hdl) == I2C_ERR_PROP_UNSUP) {
211*32002227SRobert Mustacchi 			return (strlcpy(buf, "--", buflen) < buflen);
212*32002227SRobert Mustacchi 		}
213*32002227SRobert Mustacchi 		return (B_FALSE);
214*32002227SRobert Mustacchi 	}
215*32002227SRobert Mustacchi 
216*32002227SRobert Mustacchi 	if (range->ipr_count == 0) {
217*32002227SRobert Mustacchi 		return (strlcpy(buf, "--", buflen) < buflen);
218*32002227SRobert Mustacchi 	}
219*32002227SRobert Mustacchi 
220*32002227SRobert Mustacchi 	switch (range->ipr_type) {
221*32002227SRobert Mustacchi 	case I2C_PROP_TYPE_U32:
222*32002227SRobert Mustacchi 		return (i2cadm_value_print_pos_u32(range, buf, buflen));
223*32002227SRobert Mustacchi 	case I2C_PROP_TYPE_BIT32:
224*32002227SRobert Mustacchi 		return (i2cadm_value_print_pos_bit32(info, range, buf, buflen));
225*32002227SRobert Mustacchi 	default:
226*32002227SRobert Mustacchi 		return (B_FALSE);
227*32002227SRobert Mustacchi 	}
228*32002227SRobert Mustacchi 
229*32002227SRobert Mustacchi 	return (len <= buflen);
230*32002227SRobert Mustacchi }
231*32002227SRobert Mustacchi 
232*32002227SRobert Mustacchi static void
i2cadm_controller_prop_get_usage(FILE * f)233*32002227SRobert Mustacchi i2cadm_controller_prop_get_usage(FILE *f)
234*32002227SRobert Mustacchi {
235*32002227SRobert Mustacchi 	(void) fprintf(stderr, "\ti2cadm controller prop get [-Hp] "
236*32002227SRobert Mustacchi 	    "[-o field[,...] <controller> [filter]\n");
237*32002227SRobert Mustacchi }
238*32002227SRobert Mustacchi 
239*32002227SRobert Mustacchi static void
i2cadm_controller_prop_get_help(const char * fmt,...)240*32002227SRobert Mustacchi i2cadm_controller_prop_get_help(const char *fmt, ...)
241*32002227SRobert Mustacchi {
242*32002227SRobert Mustacchi 	if (fmt != NULL) {
243*32002227SRobert Mustacchi 		va_list ap;
244*32002227SRobert Mustacchi 
245*32002227SRobert Mustacchi 		va_start(ap, fmt);
246*32002227SRobert Mustacchi 		vwarnx(fmt, ap);
247*32002227SRobert Mustacchi 		va_end(ap);
248*32002227SRobert Mustacchi 	}
249*32002227SRobert Mustacchi 
250*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  i2cadm controller prop get [-H] "
251*32002227SRobert Mustacchi 	    "[-o field[,...] [-p]] <controller> [filter...]\n\n");
252*32002227SRobert Mustacchi 	(void) fprintf(stderr, "List properties on the specified controller. "
253*32002227SRobert Mustacchi 	    "Each <filter> selects a property\nbased on its name. When "
254*32002227SRobert Mustacchi 	    "multiple filters are specified, they are treated like\nan OR. It "
255*32002227SRobert Mustacchi 	    "is an error if a filter isn't used.\n\n"
256*32002227SRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
257*32002227SRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
258*32002227SRobert Mustacchi 	    "\t-p\t\tparseable output (requires -o)\n");
259*32002227SRobert Mustacchi 	(void) fprintf(stderr, "\nThe following fields are supported:\n"
260*32002227SRobert Mustacchi 	    "\tproperty\tthe name of the property\n"
261*32002227SRobert Mustacchi 	    "\tperm\t\tthe property's permissions\n"
262*32002227SRobert Mustacchi 	    "\tvalue\t\tthe property's value\n"
263*32002227SRobert Mustacchi 	    "\tdefault\t\tthe property's default value\n"
264*32002227SRobert Mustacchi 	    "\tpossible\tthe property's possible values\n"
265*32002227SRobert Mustacchi 	    "\ttype\t\tthe property's type\n"
266*32002227SRobert Mustacchi 	    "\tctrl\t\tthe name of the controller\n"
267*32002227SRobert Mustacchi 	    "\tid\t\tthe system id for the property\n");
268*32002227SRobert Mustacchi }
269*32002227SRobert Mustacchi 
270*32002227SRobert Mustacchi typedef enum {
271*32002227SRobert Mustacchi 	I2CADM_CTRL_PROP_GET_PROP,
272*32002227SRobert Mustacchi 	I2CADM_CTRL_PROP_GET_PERM,
273*32002227SRobert Mustacchi 	I2CADM_CTRL_PROP_GET_VALUE,
274*32002227SRobert Mustacchi 	I2CADM_CTRL_PROP_GET_DEF,
275*32002227SRobert Mustacchi 	I2CADM_CTRL_PROP_GET_POS,
276*32002227SRobert Mustacchi 	I2CADM_CTRL_PROP_GET_TYPE,
277*32002227SRobert Mustacchi 	I2CADM_CTRL_PROP_GET_CTRL,
278*32002227SRobert Mustacchi 	I2CADM_CTRL_PROP_GET_ID
279*32002227SRobert Mustacchi } i2cadm_ctrl_prop_get_otype_t;
280*32002227SRobert Mustacchi 
281*32002227SRobert Mustacchi typedef struct i2cadm_ctrl_prop_get_ofmt {
282*32002227SRobert Mustacchi 	const char *icpg_ctrl;
283*32002227SRobert Mustacchi 	i2c_prop_info_t *icpg_info;
284*32002227SRobert Mustacchi 	bool icpg_valid;
285*32002227SRobert Mustacchi 	uint32_t icpg_u32;
286*32002227SRobert Mustacchi } i2cadm_ctrl_prop_get_ofmt_t;
287*32002227SRobert Mustacchi 
288*32002227SRobert Mustacchi static boolean_t
i2cadm_ctrl_prop_get_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)289*32002227SRobert Mustacchi i2cadm_ctrl_prop_get_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
290*32002227SRobert Mustacchi {
291*32002227SRobert Mustacchi 	i2cadm_ctrl_prop_get_ofmt_t *arg = ofarg->ofmt_cbarg;
292*32002227SRobert Mustacchi 	size_t len;
293*32002227SRobert Mustacchi 	uint32_t def;
294*32002227SRobert Mustacchi 
295*32002227SRobert Mustacchi 	switch (ofarg->ofmt_id) {
296*32002227SRobert Mustacchi 	case I2CADM_CTRL_PROP_GET_PROP:
297*32002227SRobert Mustacchi 		len = strlcpy(buf, i2c_prop_info_name(arg->icpg_info), buflen);
298*32002227SRobert Mustacchi 		break;
299*32002227SRobert Mustacchi 	case I2CADM_CTRL_PROP_GET_PERM:
300*32002227SRobert Mustacchi 		switch (i2c_prop_info_perm(arg->icpg_info)) {
301*32002227SRobert Mustacchi 		case I2C_PROP_PERM_RO:
302*32002227SRobert Mustacchi 			len = strlcpy(buf, "r-", buflen);
303*32002227SRobert Mustacchi 			break;
304*32002227SRobert Mustacchi 		case I2C_PROP_PERM_RW:
305*32002227SRobert Mustacchi 			len = strlcpy(buf, "rw", buflen);
306*32002227SRobert Mustacchi 			break;
307*32002227SRobert Mustacchi 		default:
308*32002227SRobert Mustacchi 			return (B_FALSE);
309*32002227SRobert Mustacchi 		}
310*32002227SRobert Mustacchi 		break;
311*32002227SRobert Mustacchi 	case I2CADM_CTRL_PROP_GET_VALUE:
312*32002227SRobert Mustacchi 		if (!arg->icpg_valid) {
313*32002227SRobert Mustacchi 			len = strlcpy(buf, "--", buflen);
314*32002227SRobert Mustacchi 			break;
315*32002227SRobert Mustacchi 		}
316*32002227SRobert Mustacchi 
317*32002227SRobert Mustacchi 		return (i2cadm_value_print(arg->icpg_info, arg->icpg_u32, buf,
318*32002227SRobert Mustacchi 		    buflen));
319*32002227SRobert Mustacchi 	case I2CADM_CTRL_PROP_GET_DEF:
320*32002227SRobert Mustacchi 		if (!i2c_prop_info_def_u32(arg->icpg_info, &def)) {
321*32002227SRobert Mustacchi 			len = strlcpy(buf, "--", buflen);
322*32002227SRobert Mustacchi 			break;
323*32002227SRobert Mustacchi 		}
324*32002227SRobert Mustacchi 
325*32002227SRobert Mustacchi 		return (i2cadm_value_print(arg->icpg_info, def, buf, buflen));
326*32002227SRobert Mustacchi 	case I2CADM_CTRL_PROP_GET_POS:
327*32002227SRobert Mustacchi 		return (i2cadm_value_print_pos(arg->icpg_info, buf, buflen));
328*32002227SRobert Mustacchi 	case I2CADM_CTRL_PROP_GET_TYPE:
329*32002227SRobert Mustacchi 		switch (i2c_prop_info_type(arg->icpg_info)) {
330*32002227SRobert Mustacchi 		case I2C_PROP_TYPE_U32:
331*32002227SRobert Mustacchi 			len = strlcpy(buf, "u32", buflen);
332*32002227SRobert Mustacchi 			break;
333*32002227SRobert Mustacchi 		case I2C_PROP_TYPE_BIT32:
334*32002227SRobert Mustacchi 			len = strlcpy(buf, "bit32", buflen);
335*32002227SRobert Mustacchi 			break;
336*32002227SRobert Mustacchi 		default:
337*32002227SRobert Mustacchi 			return (B_FALSE);
338*32002227SRobert Mustacchi 		}
339*32002227SRobert Mustacchi 		break;
340*32002227SRobert Mustacchi 	case I2CADM_CTRL_PROP_GET_CTRL:
341*32002227SRobert Mustacchi 		len = strlcpy(buf, arg->icpg_ctrl, buflen);
342*32002227SRobert Mustacchi 		break;
343*32002227SRobert Mustacchi 	case I2CADM_CTRL_PROP_GET_ID:
344*32002227SRobert Mustacchi 		len = snprintf(buf, buflen, "%u",
345*32002227SRobert Mustacchi 		    i2c_prop_info_id(arg->icpg_info));
346*32002227SRobert Mustacchi 		break;
347*32002227SRobert Mustacchi 	default:
348*32002227SRobert Mustacchi 		return (B_FALSE);
349*32002227SRobert Mustacchi 	}
350*32002227SRobert Mustacchi 
351*32002227SRobert Mustacchi 	return (len < buflen);
352*32002227SRobert Mustacchi }
353*32002227SRobert Mustacchi 
354*32002227SRobert Mustacchi static const char *i2cadm_ctrl_prop_get_fields =
355*32002227SRobert Mustacchi 	"property,perm,value,default,possible";
356*32002227SRobert Mustacchi static const ofmt_field_t i2cadm_ctrl_prop_get_ofmt[] = {
357*32002227SRobert Mustacchi 	{ "PROPERTY", 20, I2CADM_CTRL_PROP_GET_PROP,
358*32002227SRobert Mustacchi 	    i2cadm_ctrl_prop_get_ofmt_cb },
359*32002227SRobert Mustacchi 	{ "PERM", 6, I2CADM_CTRL_PROP_GET_PERM, i2cadm_ctrl_prop_get_ofmt_cb },
360*32002227SRobert Mustacchi 	{ "VALUE", 16, I2CADM_CTRL_PROP_GET_VALUE,
361*32002227SRobert Mustacchi 	    i2cadm_ctrl_prop_get_ofmt_cb },
362*32002227SRobert Mustacchi 	{ "DEFAULT", 16, I2CADM_CTRL_PROP_GET_DEF,
363*32002227SRobert Mustacchi 	    i2cadm_ctrl_prop_get_ofmt_cb },
364*32002227SRobert Mustacchi 	{ "POSSIBLE", 16, I2CADM_CTRL_PROP_GET_POS,
365*32002227SRobert Mustacchi 	    i2cadm_ctrl_prop_get_ofmt_cb },
366*32002227SRobert Mustacchi 	{ "TYPE", 6, I2CADM_CTRL_PROP_GET_TYPE, i2cadm_ctrl_prop_get_ofmt_cb },
367*32002227SRobert Mustacchi 	{ "CONTROLLER", 12, I2CADM_CTRL_PROP_GET_CTRL,
368*32002227SRobert Mustacchi 	    i2cadm_ctrl_prop_get_ofmt_cb },
369*32002227SRobert Mustacchi 	{ "ID", 8, I2CADM_CTRL_PROP_GET_ID, i2cadm_ctrl_prop_get_ofmt_cb },
370*32002227SRobert Mustacchi 	{ NULL, 0, 0, NULL }
371*32002227SRobert Mustacchi };
372*32002227SRobert Mustacchi 
373*32002227SRobert Mustacchi static int
i2cadm_controller_prop_get(int argc,char * argv[])374*32002227SRobert Mustacchi i2cadm_controller_prop_get(int argc, char *argv[])
375*32002227SRobert Mustacchi {
376*32002227SRobert Mustacchi 	int c, ret = EXIT_SUCCESS;
377*32002227SRobert Mustacchi 	uint_t flags = 0;
378*32002227SRobert Mustacchi 	boolean_t parse = B_FALSE;
379*32002227SRobert Mustacchi 	const char *fields = NULL, *cname;
380*32002227SRobert Mustacchi 	i2c_ctrl_t *ctrl;
381*32002227SRobert Mustacchi 	bool *filts = NULL;
382*32002227SRobert Mustacchi 	ofmt_status_t oferr;
383*32002227SRobert Mustacchi 	ofmt_handle_t ofmt;
384*32002227SRobert Mustacchi 
385*32002227SRobert Mustacchi 	while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
386*32002227SRobert Mustacchi 		switch (c) {
387*32002227SRobert Mustacchi 		case 'H':
388*32002227SRobert Mustacchi 			flags |= OFMT_NOHEADER;
389*32002227SRobert Mustacchi 			break;
390*32002227SRobert Mustacchi 		case 'o':
391*32002227SRobert Mustacchi 			fields = optarg;
392*32002227SRobert Mustacchi 			break;
393*32002227SRobert Mustacchi 		case 'p':
394*32002227SRobert Mustacchi 			parse = B_TRUE;
395*32002227SRobert Mustacchi 			flags |= OFMT_PARSABLE;
396*32002227SRobert Mustacchi 			break;
397*32002227SRobert Mustacchi 		case ':':
398*32002227SRobert Mustacchi 			i2cadm_controller_prop_get_help("option -%c requires "
399*32002227SRobert Mustacchi 			    "an argument", optopt);
400*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
401*32002227SRobert Mustacchi 		case '?':
402*32002227SRobert Mustacchi 			i2cadm_controller_prop_get_help("unknown option: -%c",
403*32002227SRobert Mustacchi 			    optopt);
404*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
405*32002227SRobert Mustacchi 		}
406*32002227SRobert Mustacchi 	}
407*32002227SRobert Mustacchi 
408*32002227SRobert Mustacchi 	if (parse && fields == NULL) {
409*32002227SRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
410*32002227SRobert Mustacchi 	}
411*32002227SRobert Mustacchi 
412*32002227SRobert Mustacchi 	if (!parse) {
413*32002227SRobert Mustacchi 		flags |= OFMT_WRAP;
414*32002227SRobert Mustacchi 	}
415*32002227SRobert Mustacchi 
416*32002227SRobert Mustacchi 	if (fields == NULL) {
417*32002227SRobert Mustacchi 		fields = i2cadm_ctrl_prop_get_fields;
418*32002227SRobert Mustacchi 	}
419*32002227SRobert Mustacchi 
420*32002227SRobert Mustacchi 	argc -= optind;
421*32002227SRobert Mustacchi 	argv += optind;
422*32002227SRobert Mustacchi 	if (argc == 0) {
423*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "missing required controller");
424*32002227SRobert Mustacchi 	}
425*32002227SRobert Mustacchi 
426*32002227SRobert Mustacchi 	cname = argv[0];
427*32002227SRobert Mustacchi 	argc--;
428*32002227SRobert Mustacchi 	argv++;
429*32002227SRobert Mustacchi 	if (!i2c_ctrl_init_by_path(i2cadm.i2c_hdl, cname, &ctrl)) {
430*32002227SRobert Mustacchi 		i2cadm_fatal("failed to initialize controller %s", cname);
431*32002227SRobert Mustacchi 	}
432*32002227SRobert Mustacchi 
433*32002227SRobert Mustacchi 	if (argc > 0) {
434*32002227SRobert Mustacchi 		filts = calloc(argc, sizeof (bool));
435*32002227SRobert Mustacchi 		if (filts == NULL) {
436*32002227SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
437*32002227SRobert Mustacchi 			    "filter tracking");
438*32002227SRobert Mustacchi 		}
439*32002227SRobert Mustacchi 	}
440*32002227SRobert Mustacchi 
441*32002227SRobert Mustacchi 	oferr = ofmt_open(fields, i2cadm_ctrl_prop_get_ofmt, flags, 0, &ofmt);
442*32002227SRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, i2cadm_ofmt_errx, warnx);
443*32002227SRobert Mustacchi 
444*32002227SRobert Mustacchi 	uint32_t nprops = i2c_ctrl_nprops(ctrl);
445*32002227SRobert Mustacchi 	for (uint32_t i = 0; i < nprops; i++) {
446*32002227SRobert Mustacchi 		i2c_prop_info_t *info;
447*32002227SRobert Mustacchi 		i2cadm_ctrl_prop_get_ofmt_t arg;
448*32002227SRobert Mustacchi 
449*32002227SRobert Mustacchi 		if (!i2c_prop_info(ctrl, i, &info)) {
450*32002227SRobert Mustacchi 			i2cadm_warn("failed to get property %u information", i);
451*32002227SRobert Mustacchi 			ret = EXIT_FAILURE;
452*32002227SRobert Mustacchi 			continue;
453*32002227SRobert Mustacchi 		}
454*32002227SRobert Mustacchi 
455*32002227SRobert Mustacchi 		if (argc > 0) {
456*32002227SRobert Mustacchi 			const char *name = i2c_prop_info_name(info);
457*32002227SRobert Mustacchi 			bool match = false;
458*32002227SRobert Mustacchi 
459*32002227SRobert Mustacchi 			for (int i = 0; i < argc; i++) {
460*32002227SRobert Mustacchi 				if (strcmp(argv[i], name) == 0) {
461*32002227SRobert Mustacchi 					match = true;
462*32002227SRobert Mustacchi 					filts[i] = true;
463*32002227SRobert Mustacchi 				}
464*32002227SRobert Mustacchi 			}
465*32002227SRobert Mustacchi 
466*32002227SRobert Mustacchi 			if (!match) {
467*32002227SRobert Mustacchi 				i2c_prop_info_free(info);
468*32002227SRobert Mustacchi 				continue;
469*32002227SRobert Mustacchi 			}
470*32002227SRobert Mustacchi 		}
471*32002227SRobert Mustacchi 
472*32002227SRobert Mustacchi 		(void) memset(&arg, 0, sizeof (arg));
473*32002227SRobert Mustacchi 		arg.icpg_ctrl = cname;
474*32002227SRobert Mustacchi 		arg.icpg_info = info;
475*32002227SRobert Mustacchi 
476*32002227SRobert Mustacchi 		if (i2c_prop_info_sup(info)) {
477*32002227SRobert Mustacchi 			i2c_prop_type_t type = i2c_prop_info_type(info);
478*32002227SRobert Mustacchi 			if (type == I2C_PROP_TYPE_U32 ||
479*32002227SRobert Mustacchi 			    type == I2C_PROP_TYPE_BIT32) {
480*32002227SRobert Mustacchi 				size_t len = sizeof (uint32_t);
481*32002227SRobert Mustacchi 				if (!i2c_prop_get(ctrl, i, &arg.icpg_u32,
482*32002227SRobert Mustacchi 				    &len)) {
483*32002227SRobert Mustacchi 					i2cadm_warn("failed to get property "
484*32002227SRobert Mustacchi 					    "%s (%u)", i2c_prop_info_name(info),
485*32002227SRobert Mustacchi 					    i);
486*32002227SRobert Mustacchi 					ret = EXIT_FAILURE;
487*32002227SRobert Mustacchi 				} else if (len != sizeof (uint32_t)) {
488*32002227SRobert Mustacchi 					warnx("property %s (%u) returned "
489*32002227SRobert Mustacchi 					    "unexpected property size of %zu, "
490*32002227SRobert Mustacchi 					    "but %zu was expected, unable to "
491*32002227SRobert Mustacchi 					    "print value",
492*32002227SRobert Mustacchi 					    i2c_prop_info_name(info), i, len,
493*32002227SRobert Mustacchi 					    sizeof (uint32_t));
494*32002227SRobert Mustacchi 					ret = EXIT_FAILURE;
495*32002227SRobert Mustacchi 				} else {
496*32002227SRobert Mustacchi 					arg.icpg_valid = true;
497*32002227SRobert Mustacchi 				}
498*32002227SRobert Mustacchi 			} else {
499*32002227SRobert Mustacchi 				warnx("property %s (%u) has unknown type 0x%x, "
500*32002227SRobert Mustacchi 				    "cannot get or display value",
501*32002227SRobert Mustacchi 				    i2c_prop_info_name(info), i, type);
502*32002227SRobert Mustacchi 				ret = EXIT_FAILURE;
503*32002227SRobert Mustacchi 			}
504*32002227SRobert Mustacchi 		}
505*32002227SRobert Mustacchi 
506*32002227SRobert Mustacchi 		ofmt_print(ofmt, &arg);
507*32002227SRobert Mustacchi 		free(info);
508*32002227SRobert Mustacchi 	}
509*32002227SRobert Mustacchi 
510*32002227SRobert Mustacchi 	for (int i = 0; i < argc; i++) {
511*32002227SRobert Mustacchi 		if (!filts[i]) {
512*32002227SRobert Mustacchi 			warnx("filter '%s' did not match any properties",
513*32002227SRobert Mustacchi 			    argv[i]);
514*32002227SRobert Mustacchi 			ret = EXIT_FAILURE;
515*32002227SRobert Mustacchi 		}
516*32002227SRobert Mustacchi 	}
517*32002227SRobert Mustacchi 
518*32002227SRobert Mustacchi 	free(filts);
519*32002227SRobert Mustacchi 	ofmt_close(ofmt);
520*32002227SRobert Mustacchi 	i2c_ctrl_fini(ctrl);
521*32002227SRobert Mustacchi 	return (ret);
522*32002227SRobert Mustacchi }
523*32002227SRobert Mustacchi 
524*32002227SRobert Mustacchi static void
i2cadm_controller_prop_set_usage(FILE * f)525*32002227SRobert Mustacchi i2cadm_controller_prop_set_usage(FILE *f)
526*32002227SRobert Mustacchi {
527*32002227SRobert Mustacchi 	(void) fprintf(stderr, "\ti2cadm controller prop set <controller> "
528*32002227SRobert Mustacchi 	    "<property>=<value>\n");
529*32002227SRobert Mustacchi }
530*32002227SRobert Mustacchi 
531*32002227SRobert Mustacchi static int
i2cadm_controller_prop_set(int argc,char * argv[])532*32002227SRobert Mustacchi i2cadm_controller_prop_set(int argc, char *argv[])
533*32002227SRobert Mustacchi {
534*32002227SRobert Mustacchi 	i2c_ctrl_t *ctrl;
535*32002227SRobert Mustacchi 	i2c_prop_info_t *info;
536*32002227SRobert Mustacchi 	char *prop, *val;
537*32002227SRobert Mustacchi 	size_t buflen = 0;
538*32002227SRobert Mustacchi 	void *buf = NULL;
539*32002227SRobert Mustacchi 
540*32002227SRobert Mustacchi 	if (argc == 0) {
541*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "missing required controller and property");
542*32002227SRobert Mustacchi 	} else if (argc == 1) {
543*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "missing required property");
544*32002227SRobert Mustacchi 	} else if (argc > 2) {
545*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "only one property can be set at a time, "
546*32002227SRobert Mustacchi 		    "extraneous arguments start with %s", argv[2]);
547*32002227SRobert Mustacchi 	}
548*32002227SRobert Mustacchi 
549*32002227SRobert Mustacchi 	if (!i2c_ctrl_init_by_path(i2cadm.i2c_hdl, argv[0], &ctrl)) {
550*32002227SRobert Mustacchi 		i2cadm_fatal("failed to initialize controller %s", argv[0]);
551*32002227SRobert Mustacchi 	}
552*32002227SRobert Mustacchi 
553*32002227SRobert Mustacchi 	prop = argv[1];
554*32002227SRobert Mustacchi 	val = strchr(prop, '=');
555*32002227SRobert Mustacchi 	if (val == NULL) {
556*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "could not parse property name and value "
557*32002227SRobert Mustacchi 		    "from %s: missing = separator", argv[1]);
558*32002227SRobert Mustacchi 	}
559*32002227SRobert Mustacchi 	*val = '\0';
560*32002227SRobert Mustacchi 	val++;
561*32002227SRobert Mustacchi 
562*32002227SRobert Mustacchi 	if (!i2c_prop_info_by_name(ctrl, prop, &info)) {
563*32002227SRobert Mustacchi 		i2cadm_fatal("failed to get information for property %s", prop);
564*32002227SRobert Mustacchi 	}
565*32002227SRobert Mustacchi 
566*32002227SRobert Mustacchi 	if (!i2c_prop_info_sup(info)) {
567*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "controller %s does not support property %s",
568*32002227SRobert Mustacchi 		    argv[0], prop);
569*32002227SRobert Mustacchi 	}
570*32002227SRobert Mustacchi 
571*32002227SRobert Mustacchi 	if (i2c_prop_info_perm(info) != I2C_PROP_PERM_RW) {
572*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "property %s is read-only on controller %s",
573*32002227SRobert Mustacchi 		    prop, argv[0]);
574*32002227SRobert Mustacchi 	}
575*32002227SRobert Mustacchi 
576*32002227SRobert Mustacchi 	/*
577*32002227SRobert Mustacchi 	 * See if this property is one that we parse via string transformations.
578*32002227SRobert Mustacchi 	 */
579*32002227SRobert Mustacchi 	switch (i2c_prop_info_id(info)) {
580*32002227SRobert Mustacchi 	case I2C_PROP_BUS_SPEED:
581*32002227SRobert Mustacchi 		for (size_t i = 0; i < ARRAY_SIZE(speed_op_map); i++) {
582*32002227SRobert Mustacchi 			if (strcmp(val, speed_op_map[i].om_name) == 0) {
583*32002227SRobert Mustacchi 				buflen = sizeof (uint32_t);
584*32002227SRobert Mustacchi 				buf = calloc(1, buflen);
585*32002227SRobert Mustacchi 				if (buf == NULL) {
586*32002227SRobert Mustacchi 					errx(EXIT_FAILURE, "failed to allocate "
587*32002227SRobert Mustacchi 					    "%zu bytes of memory to hold %s "
588*32002227SRobert Mustacchi 					    "property value", buflen, prop);
589*32002227SRobert Mustacchi 				}
590*32002227SRobert Mustacchi 
591*32002227SRobert Mustacchi 				(void) memcpy(buf, &speed_op_map[i].om_op,
592*32002227SRobert Mustacchi 				    sizeof (uint32_t));
593*32002227SRobert Mustacchi 			}
594*32002227SRobert Mustacchi 		}
595*32002227SRobert Mustacchi 		break;
596*32002227SRobert Mustacchi 	default:
597*32002227SRobert Mustacchi 		break;
598*32002227SRobert Mustacchi 	}
599*32002227SRobert Mustacchi 
600*32002227SRobert Mustacchi 	if (buf == NULL) {
601*32002227SRobert Mustacchi 		uint32_t u32;
602*32002227SRobert Mustacchi 		const char *errstr;
603*32002227SRobert Mustacchi 
604*32002227SRobert Mustacchi 		switch (i2c_prop_info_type(info)) {
605*32002227SRobert Mustacchi 		case I2C_PROP_TYPE_U32:
606*32002227SRobert Mustacchi 		case I2C_PROP_TYPE_BIT32:
607*32002227SRobert Mustacchi 			u32 = (uint32_t)strtonumx(val, 0, UINT32_MAX, &errstr,
608*32002227SRobert Mustacchi 			    0);
609*32002227SRobert Mustacchi 			if (errstr != NULL) {
610*32002227SRobert Mustacchi 				errx(EXIT_FAILURE, "invalid 32-bit %s property "
611*32002227SRobert Mustacchi 				    "values: %s is %s", prop, val, errstr);
612*32002227SRobert Mustacchi 			}
613*32002227SRobert Mustacchi 
614*32002227SRobert Mustacchi 			buflen = sizeof (uint32_t);
615*32002227SRobert Mustacchi 			buf = calloc(1, buflen);
616*32002227SRobert Mustacchi 			if (buf == NULL) {
617*32002227SRobert Mustacchi 				errx(EXIT_FAILURE, "failed to allocate %zu "
618*32002227SRobert Mustacchi 				    "bytes of memory to hold %s property value",
619*32002227SRobert Mustacchi 				    buflen, prop);
620*32002227SRobert Mustacchi 			}
621*32002227SRobert Mustacchi 
622*32002227SRobert Mustacchi 			(void) memcpy(buf, &u32, sizeof (uint32_t));
623*32002227SRobert Mustacchi 			break;
624*32002227SRobert Mustacchi 		default:
625*32002227SRobert Mustacchi 			errx(EXIT_FAILURE, "unable to parse property %s type "
626*32002227SRobert Mustacchi 			    "0x%x", prop, i2c_prop_info_type(info));
627*32002227SRobert Mustacchi 
628*32002227SRobert Mustacchi 		}
629*32002227SRobert Mustacchi 	}
630*32002227SRobert Mustacchi 
631*32002227SRobert Mustacchi 	if (!i2c_prop_set(ctrl, i2c_prop_info_id(info), buf, buflen)) {
632*32002227SRobert Mustacchi 		i2cadm_fatal("failed to set property %s to %s", prop, val);
633*32002227SRobert Mustacchi 	}
634*32002227SRobert Mustacchi 
635*32002227SRobert Mustacchi 	i2c_prop_info_free(info);
636*32002227SRobert Mustacchi 	i2c_ctrl_fini(ctrl);
637*32002227SRobert Mustacchi 	return (EXIT_SUCCESS);
638*32002227SRobert Mustacchi }
639*32002227SRobert Mustacchi 
640*32002227SRobert Mustacchi static i2cadm_cmdtab_t i2cadm_ctrl_prop_cmds[] = {
641*32002227SRobert Mustacchi 	{ "get", i2cadm_controller_prop_get, i2cadm_controller_prop_get_usage },
642*32002227SRobert Mustacchi 	{ "set", i2cadm_controller_prop_set, i2cadm_controller_prop_set_usage }
643*32002227SRobert Mustacchi };
644*32002227SRobert Mustacchi 
645*32002227SRobert Mustacchi static int
i2cadm_controller_prop(int argc,char * argv[])646*32002227SRobert Mustacchi i2cadm_controller_prop(int argc, char *argv[])
647*32002227SRobert Mustacchi {
648*32002227SRobert Mustacchi 	return (i2cadm_walk_tab(i2cadm_ctrl_prop_cmds,
649*32002227SRobert Mustacchi 	    ARRAY_SIZE(i2cadm_ctrl_prop_cmds), argc, argv));
650*32002227SRobert Mustacchi }
651*32002227SRobert Mustacchi 
652*32002227SRobert Mustacchi static void
i2cadm_controller_prop_usage(FILE * f)653*32002227SRobert Mustacchi i2cadm_controller_prop_usage(FILE *f)
654*32002227SRobert Mustacchi {
655*32002227SRobert Mustacchi 	i2cadm_walk_usage(i2cadm_ctrl_prop_cmds,
656*32002227SRobert Mustacchi 	    ARRAY_SIZE(i2cadm_ctrl_prop_cmds), f);
657*32002227SRobert Mustacchi }
658*32002227SRobert Mustacchi 
659*32002227SRobert Mustacchi static void
i2cadm_controller_list_usage(FILE * f)660*32002227SRobert Mustacchi i2cadm_controller_list_usage(FILE *f)
661*32002227SRobert Mustacchi {
662*32002227SRobert Mustacchi 	(void) fprintf(f, "\ti2cadm controller list [-H] [-o field,[...] [-p]] "
663*32002227SRobert Mustacchi 	    "[filter]\n");
664*32002227SRobert Mustacchi }
665*32002227SRobert Mustacchi 
666*32002227SRobert Mustacchi static void
i2cadm_controller_list_help(const char * fmt,...)667*32002227SRobert Mustacchi i2cadm_controller_list_help(const char *fmt, ...)
668*32002227SRobert Mustacchi {
669*32002227SRobert Mustacchi 	if (fmt != NULL) {
670*32002227SRobert Mustacchi 		va_list ap;
671*32002227SRobert Mustacchi 
672*32002227SRobert Mustacchi 		va_start(ap, fmt);
673*32002227SRobert Mustacchi 		vwarnx(fmt, ap);
674*32002227SRobert Mustacchi 		va_end(ap);
675*32002227SRobert Mustacchi 	}
676*32002227SRobert Mustacchi 
677*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  i2cadm controller list [-H] "
678*32002227SRobert Mustacchi 	    "[-o field[,...] [-p]] [filter...]\n\n");
679*32002227SRobert Mustacchi 	(void) fprintf(stderr, "List I2C Controllers. Each <filter> selects a "
680*32002227SRobert Mustacchi 	    "set of controllers to show and\ncan be a controller or driver "
681*32002227SRobert Mustacchi 	    "name. When multiple filters are specified, they\nare treated like "
682*32002227SRobert Mustacchi 	    "an OR. It is an error if a filter isn't used.\n\n"
683*32002227SRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
684*32002227SRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
685*32002227SRobert Mustacchi 	    "\t-p\t\tparseable output (requires -o)\n");
686*32002227SRobert Mustacchi 	(void) fprintf(stderr, "\nThe following fields are supported:\n"
687*32002227SRobert Mustacchi 	    "\tname\t\tthe controller's name\n"
688*32002227SRobert Mustacchi 	    "\ttype\t\tthe controller's type (e.g. i2c, smbus)\n"
689*32002227SRobert Mustacchi 	    "\tspeed\t\tthe controller's current speed\n"
690*32002227SRobert Mustacchi 	    "\tdriver\t\tthe name of the driver for the controller\n"
691*32002227SRobert Mustacchi 	    "\tinstance\tthe driver instance for the controller\n"
692*32002227SRobert Mustacchi 	    "\tprovider\tthe /devices path of the provider\n");
693*32002227SRobert Mustacchi }
694*32002227SRobert Mustacchi 
695*32002227SRobert Mustacchi typedef enum {
696*32002227SRobert Mustacchi 	I2CADM_CTRL_LIST_NAME,
697*32002227SRobert Mustacchi 	I2CADM_CTRL_LIST_TYPE,
698*32002227SRobert Mustacchi 	I2CADM_CTRL_LIST_SPEED,
699*32002227SRobert Mustacchi 	I2CADM_CTRL_LIST_NPORTS,
700*32002227SRobert Mustacchi 	I2CADM_CTRL_LIST_DRIVER,
701*32002227SRobert Mustacchi 	I2CADM_CTRL_LIST_INSTANCE,
702*32002227SRobert Mustacchi 	I2CADM_CTRL_LIST_PROVIDER
703*32002227SRobert Mustacchi } i2cadm_ctrl_list_otype_t;
704*32002227SRobert Mustacchi 
705*32002227SRobert Mustacchi typedef struct i2cadm_ctrl_list_ofmt {
706*32002227SRobert Mustacchi 	di_node_t icl_nexus;
707*32002227SRobert Mustacchi 	di_node_t icl_drv;
708*32002227SRobert Mustacchi 	i2c_ctrl_t *icl_ctrl;
709*32002227SRobert Mustacchi 	uint32_t icl_speed;
710*32002227SRobert Mustacchi 	uint32_t icl_type;
711*32002227SRobert Mustacchi 	uint32_t icl_nports;
712*32002227SRobert Mustacchi } i2cadm_ctrl_list_ofmt_t;
713*32002227SRobert Mustacchi 
714*32002227SRobert Mustacchi static boolean_t
i2cadm_ctrl_list_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)715*32002227SRobert Mustacchi i2cadm_ctrl_list_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
716*32002227SRobert Mustacchi {
717*32002227SRobert Mustacchi 	i2cadm_ctrl_list_ofmt_t *arg = ofarg->ofmt_cbarg;
718*32002227SRobert Mustacchi 	size_t len;
719*32002227SRobert Mustacchi 
720*32002227SRobert Mustacchi 	switch (ofarg->ofmt_id) {
721*32002227SRobert Mustacchi 	case I2CADM_CTRL_LIST_NAME:
722*32002227SRobert Mustacchi 		len = strlcat(buf, di_bus_addr(arg->icl_nexus), buflen);
723*32002227SRobert Mustacchi 		break;
724*32002227SRobert Mustacchi 	case I2CADM_CTRL_LIST_TYPE:
725*32002227SRobert Mustacchi 		return (i2cadm_map_to_str_one(arg->icl_type, buf, buflen,
726*32002227SRobert Mustacchi 		    type_op_map, ARRAY_SIZE(type_op_map)));
727*32002227SRobert Mustacchi 	case I2CADM_CTRL_LIST_SPEED:
728*32002227SRobert Mustacchi 		return (i2cadm_map_to_str_one(arg->icl_speed, buf, buflen,
729*32002227SRobert Mustacchi 		    speed_op_map, ARRAY_SIZE(speed_op_map)));
730*32002227SRobert Mustacchi 	case I2CADM_CTRL_LIST_NPORTS:
731*32002227SRobert Mustacchi 		len = snprintf(buf, buflen, "%u", arg->icl_nports);
732*32002227SRobert Mustacchi 		break;
733*32002227SRobert Mustacchi 	case I2CADM_CTRL_LIST_DRIVER:
734*32002227SRobert Mustacchi 		len = strlcat(buf, di_driver_name(arg->icl_drv), buflen);
735*32002227SRobert Mustacchi 		break;
736*32002227SRobert Mustacchi 	case I2CADM_CTRL_LIST_INSTANCE:
737*32002227SRobert Mustacchi 		len = snprintf(buf, buflen, "%s%d",
738*32002227SRobert Mustacchi 		    di_driver_name(arg->icl_drv), di_instance(arg->icl_drv));
739*32002227SRobert Mustacchi 		break;
740*32002227SRobert Mustacchi 	case I2CADM_CTRL_LIST_PROVIDER:
741*32002227SRobert Mustacchi 		len = strlcat(buf, i2c_ctrl_path(arg->icl_ctrl), buflen);
742*32002227SRobert Mustacchi 		break;
743*32002227SRobert Mustacchi 	default:
744*32002227SRobert Mustacchi 		return (B_FALSE);
745*32002227SRobert Mustacchi 	}
746*32002227SRobert Mustacchi 
747*32002227SRobert Mustacchi 	return (len < buflen);
748*32002227SRobert Mustacchi }
749*32002227SRobert Mustacchi 
750*32002227SRobert Mustacchi static const char *i2cadm_ctrl_list_fields = "name,type,speed,nports,provider";
751*32002227SRobert Mustacchi static const ofmt_field_t i2cadm_ctrl_list_ofmt[] = {
752*32002227SRobert Mustacchi 	{ "NAME", 12, I2CADM_CTRL_LIST_NAME, i2cadm_ctrl_list_ofmt_cb },
753*32002227SRobert Mustacchi 	{ "TYPE", 10, I2CADM_CTRL_LIST_TYPE, i2cadm_ctrl_list_ofmt_cb },
754*32002227SRobert Mustacchi 	{ "SPEED", 12, I2CADM_CTRL_LIST_SPEED, i2cadm_ctrl_list_ofmt_cb },
755*32002227SRobert Mustacchi 	{ "NPORTS", 8, I2CADM_CTRL_LIST_NPORTS, i2cadm_ctrl_list_ofmt_cb },
756*32002227SRobert Mustacchi 	{ "DRIVER", 10, I2CADM_CTRL_LIST_DRIVER, i2cadm_ctrl_list_ofmt_cb },
757*32002227SRobert Mustacchi 	{ "INSTANCE", 16, I2CADM_CTRL_LIST_INSTANCE, i2cadm_ctrl_list_ofmt_cb },
758*32002227SRobert Mustacchi 	{ "PROVIDER", 40, I2CADM_CTRL_LIST_PROVIDER, i2cadm_ctrl_list_ofmt_cb },
759*32002227SRobert Mustacchi 	{ NULL, 0, 0, NULL }
760*32002227SRobert Mustacchi };
761*32002227SRobert Mustacchi 
762*32002227SRobert Mustacchi static int
i2cadm_controller_list(int argc,char * argv[])763*32002227SRobert Mustacchi i2cadm_controller_list(int argc, char *argv[])
764*32002227SRobert Mustacchi {
765*32002227SRobert Mustacchi 	int c, ret = EXIT_SUCCESS;
766*32002227SRobert Mustacchi 	uint_t flags = 0;
767*32002227SRobert Mustacchi 	boolean_t parse = B_FALSE;
768*32002227SRobert Mustacchi 	const char *fields = NULL;
769*32002227SRobert Mustacchi 	bool *filts = NULL, print = false;
770*32002227SRobert Mustacchi 	ofmt_status_t oferr;
771*32002227SRobert Mustacchi 	ofmt_handle_t ofmt;
772*32002227SRobert Mustacchi 	i2c_ctrl_iter_t *iter;
773*32002227SRobert Mustacchi 	i2c_iter_t iret;
774*32002227SRobert Mustacchi 	const i2c_ctrl_disc_t *disc;
775*32002227SRobert Mustacchi 
776*32002227SRobert Mustacchi 	while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
777*32002227SRobert Mustacchi 		switch (c) {
778*32002227SRobert Mustacchi 		case 'H':
779*32002227SRobert Mustacchi 			flags |= OFMT_NOHEADER;
780*32002227SRobert Mustacchi 			break;
781*32002227SRobert Mustacchi 		case 'o':
782*32002227SRobert Mustacchi 			fields = optarg;
783*32002227SRobert Mustacchi 			break;
784*32002227SRobert Mustacchi 		case 'p':
785*32002227SRobert Mustacchi 			parse = B_TRUE;
786*32002227SRobert Mustacchi 			flags |= OFMT_PARSABLE;
787*32002227SRobert Mustacchi 			break;
788*32002227SRobert Mustacchi 		case ':':
789*32002227SRobert Mustacchi 			i2cadm_controller_list_help("option -%c requires an "
790*32002227SRobert Mustacchi 			    "argument", optopt);
791*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
792*32002227SRobert Mustacchi 		case '?':
793*32002227SRobert Mustacchi 			i2cadm_controller_list_help("unknown option: -%c",
794*32002227SRobert Mustacchi 			    optopt);
795*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
796*32002227SRobert Mustacchi 		}
797*32002227SRobert Mustacchi 	}
798*32002227SRobert Mustacchi 
799*32002227SRobert Mustacchi 	if (parse && fields == NULL) {
800*32002227SRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
801*32002227SRobert Mustacchi 	}
802*32002227SRobert Mustacchi 
803*32002227SRobert Mustacchi 	if (!parse) {
804*32002227SRobert Mustacchi 		flags |= OFMT_WRAP;
805*32002227SRobert Mustacchi 	}
806*32002227SRobert Mustacchi 
807*32002227SRobert Mustacchi 	if (fields == NULL) {
808*32002227SRobert Mustacchi 		fields = i2cadm_ctrl_list_fields;
809*32002227SRobert Mustacchi 	}
810*32002227SRobert Mustacchi 
811*32002227SRobert Mustacchi 	argc -= optind;
812*32002227SRobert Mustacchi 	argv += optind;
813*32002227SRobert Mustacchi 
814*32002227SRobert Mustacchi 	if (argc > 0) {
815*32002227SRobert Mustacchi 		filts = calloc(argc, sizeof (bool));
816*32002227SRobert Mustacchi 		if (filts == NULL) {
817*32002227SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
818*32002227SRobert Mustacchi 			    "filter tracking");
819*32002227SRobert Mustacchi 		}
820*32002227SRobert Mustacchi 	}
821*32002227SRobert Mustacchi 
822*32002227SRobert Mustacchi 	oferr = ofmt_open(fields, i2cadm_ctrl_list_ofmt, flags, 0, &ofmt);
823*32002227SRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, i2cadm_ofmt_errx, warnx);
824*32002227SRobert Mustacchi 
825*32002227SRobert Mustacchi 	if (!i2c_ctrl_discover_init(i2cadm.i2c_hdl, &iter)) {
826*32002227SRobert Mustacchi 		i2cadm_fatal("failed to initialize controller walk");
827*32002227SRobert Mustacchi 	}
828*32002227SRobert Mustacchi 
829*32002227SRobert Mustacchi 	while ((iret = i2c_ctrl_discover_step(iter, &disc)) == I2C_ITER_VALID) {
830*32002227SRobert Mustacchi 		i2cadm_ctrl_list_ofmt_t arg;
831*32002227SRobert Mustacchi 		i2c_ctrl_t *ctrl;
832*32002227SRobert Mustacchi 
833*32002227SRobert Mustacchi 		(void) memset(&arg, 0, sizeof (arg));
834*32002227SRobert Mustacchi 		arg.icl_nexus = i2c_ctrl_disc_devi(disc);
835*32002227SRobert Mustacchi 		arg.icl_drv = di_parent_node(arg.icl_nexus);
836*32002227SRobert Mustacchi 
837*32002227SRobert Mustacchi 		if (argc > 0) {
838*32002227SRobert Mustacchi 			const char *name = di_bus_addr(arg.icl_nexus);
839*32002227SRobert Mustacchi 			const char *drv = di_driver_name(arg.icl_drv);
840*32002227SRobert Mustacchi 			bool match = false;
841*32002227SRobert Mustacchi 
842*32002227SRobert Mustacchi 			for (int i = 0; i < argc; i++) {
843*32002227SRobert Mustacchi 				if (strcmp(argv[i], name) == 0 ||
844*32002227SRobert Mustacchi 				    strcmp(argv[i], drv) == 0) {
845*32002227SRobert Mustacchi 					match = true;
846*32002227SRobert Mustacchi 					filts[i] = true;
847*32002227SRobert Mustacchi 				}
848*32002227SRobert Mustacchi 			}
849*32002227SRobert Mustacchi 
850*32002227SRobert Mustacchi 			if (!match) {
851*32002227SRobert Mustacchi 				continue;
852*32002227SRobert Mustacchi 			}
853*32002227SRobert Mustacchi 		}
854*32002227SRobert Mustacchi 
855*32002227SRobert Mustacchi 		if (!i2c_ctrl_init(i2cadm.i2c_hdl, arg.icl_nexus, &ctrl)) {
856*32002227SRobert Mustacchi 			i2cadm_warn("failed to initialize controller %s",
857*32002227SRobert Mustacchi 			    di_bus_addr(arg.icl_nexus));
858*32002227SRobert Mustacchi 			continue;
859*32002227SRobert Mustacchi 		}
860*32002227SRobert Mustacchi 
861*32002227SRobert Mustacchi 		size_t len = sizeof (uint32_t);
862*32002227SRobert Mustacchi 		if (!i2c_prop_get(ctrl, I2C_PROP_BUS_SPEED, &arg.icl_speed,
863*32002227SRobert Mustacchi 		    &len)) {
864*32002227SRobert Mustacchi 			i2cadm_warn("failed to get controller %s speed",
865*32002227SRobert Mustacchi 			    di_bus_addr(arg.icl_nexus));
866*32002227SRobert Mustacchi 			i2c_ctrl_fini(ctrl);
867*32002227SRobert Mustacchi 			continue;
868*32002227SRobert Mustacchi 		}
869*32002227SRobert Mustacchi 		VERIFY3U(len, ==, sizeof (uint32_t));
870*32002227SRobert Mustacchi 
871*32002227SRobert Mustacchi 		if (!i2c_prop_get(ctrl, I2C_PROP_TYPE, &arg.icl_type, &len)) {
872*32002227SRobert Mustacchi 			i2cadm_warn("failed to get controller %s type",
873*32002227SRobert Mustacchi 			    di_bus_addr(arg.icl_nexus));
874*32002227SRobert Mustacchi 			i2c_ctrl_fini(ctrl);
875*32002227SRobert Mustacchi 			continue;
876*32002227SRobert Mustacchi 		}
877*32002227SRobert Mustacchi 		VERIFY3U(len, ==, sizeof (uint32_t));
878*32002227SRobert Mustacchi 
879*32002227SRobert Mustacchi 		if (!i2c_prop_get(ctrl, I2C_PROP_NPORTS, &arg.icl_nports,
880*32002227SRobert Mustacchi 		    &len)) {
881*32002227SRobert Mustacchi 			i2cadm_warn("failed to get controller %s ports",
882*32002227SRobert Mustacchi 			    di_bus_addr(arg.icl_nexus));
883*32002227SRobert Mustacchi 			i2c_ctrl_fini(ctrl);
884*32002227SRobert Mustacchi 			continue;
885*32002227SRobert Mustacchi 		}
886*32002227SRobert Mustacchi 		VERIFY3U(len, ==, sizeof (uint32_t));
887*32002227SRobert Mustacchi 
888*32002227SRobert Mustacchi 		arg.icl_ctrl = ctrl;
889*32002227SRobert Mustacchi 		ofmt_print(ofmt, &arg);
890*32002227SRobert Mustacchi 		i2c_ctrl_fini(ctrl);
891*32002227SRobert Mustacchi 		print = true;
892*32002227SRobert Mustacchi 	}
893*32002227SRobert Mustacchi 
894*32002227SRobert Mustacchi 	if (iret == I2C_ITER_ERROR) {
895*32002227SRobert Mustacchi 		i2cadm_warn("failed to iterate controllers");
896*32002227SRobert Mustacchi 		ret = EXIT_FAILURE;
897*32002227SRobert Mustacchi 	}
898*32002227SRobert Mustacchi 
899*32002227SRobert Mustacchi 	for (int i = 0; i < argc; i++) {
900*32002227SRobert Mustacchi 		if (!filts[i]) {
901*32002227SRobert Mustacchi 			warnx("filter '%s' did not match any controllers",
902*32002227SRobert Mustacchi 			    argv[i]);
903*32002227SRobert Mustacchi 			ret = EXIT_FAILURE;
904*32002227SRobert Mustacchi 		}
905*32002227SRobert Mustacchi 	}
906*32002227SRobert Mustacchi 
907*32002227SRobert Mustacchi 	if (!print && argc == 0) {
908*32002227SRobert Mustacchi 		warnx("no controllers found");
909*32002227SRobert Mustacchi 		ret = EXIT_FAILURE;
910*32002227SRobert Mustacchi 	}
911*32002227SRobert Mustacchi 
912*32002227SRobert Mustacchi 	free(filts);
913*32002227SRobert Mustacchi 	ofmt_close(ofmt);
914*32002227SRobert Mustacchi 	i2c_ctrl_discover_fini(iter);
915*32002227SRobert Mustacchi 	return (ret);
916*32002227SRobert Mustacchi }
917*32002227SRobert Mustacchi 
918*32002227SRobert Mustacchi static i2cadm_cmdtab_t i2cadm_ctrl_cmds[] = {
919*32002227SRobert Mustacchi 	{ "list", i2cadm_controller_list, i2cadm_controller_list_usage },
920*32002227SRobert Mustacchi 	{ "prop", i2cadm_controller_prop, i2cadm_controller_prop_usage }
921*32002227SRobert Mustacchi };
922*32002227SRobert Mustacchi 
923*32002227SRobert Mustacchi int
i2cadm_controller(int argc,char * argv[])924*32002227SRobert Mustacchi i2cadm_controller(int argc, char *argv[])
925*32002227SRobert Mustacchi {
926*32002227SRobert Mustacchi 	return (i2cadm_walk_tab(i2cadm_ctrl_cmds, ARRAY_SIZE(i2cadm_ctrl_cmds),
927*32002227SRobert Mustacchi 	    argc, argv));
928*32002227SRobert Mustacchi }
929*32002227SRobert Mustacchi 
930*32002227SRobert Mustacchi void
i2cadm_controller_usage(FILE * f)931*32002227SRobert Mustacchi i2cadm_controller_usage(FILE *f)
932*32002227SRobert Mustacchi {
933*32002227SRobert Mustacchi 	i2cadm_walk_usage(i2cadm_ctrl_cmds, ARRAY_SIZE(i2cadm_ctrl_cmds), f);
934*32002227SRobert Mustacchi }
935