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