xref: /illumos-gate/usr/src/cmd/i2cadm/i2cadm_device.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 device related operations.
18*32002227SRobert Mustacchi  */
19*32002227SRobert Mustacchi 
20*32002227SRobert Mustacchi #include <err.h>
21*32002227SRobert Mustacchi #include <stdio.h>
22*32002227SRobert Mustacchi #include <stdarg.h>
23*32002227SRobert Mustacchi #include <string.h>
24*32002227SRobert Mustacchi #include <sys/sysmacros.h>
25*32002227SRobert Mustacchi #include <ofmt.h>
26*32002227SRobert Mustacchi 
27*32002227SRobert Mustacchi #include "i2cadm.h"
28*32002227SRobert Mustacchi 
29*32002227SRobert Mustacchi /*
30*32002227SRobert Mustacchi  * Attempt to apply filters. We accept the following filters that are trying to
31*32002227SRobert Mustacchi  * match devices:
32*32002227SRobert Mustacchi  *
33*32002227SRobert Mustacchi  *  - Matching a specific address
34*32002227SRobert Mustacchi  *  - Matching a portion of a device path
35*32002227SRobert Mustacchi  *  - Matching a specific driver or instance
36*32002227SRobert Mustacchi  *  - Matching a node name
37*32002227SRobert Mustacchi  *
38*32002227SRobert Mustacchi  * These filters are shared between both device list and device addrs.
39*32002227SRobert Mustacchi  */
40*32002227SRobert Mustacchi static bool
i2cadm_device_filt(const i2c_dev_info_t * info,int nfilts,char ** filts,bool * used)41*32002227SRobert Mustacchi i2cadm_device_filt(const i2c_dev_info_t *info, int nfilts, char **filts,
42*32002227SRobert Mustacchi     bool *used)
43*32002227SRobert Mustacchi {
44*32002227SRobert Mustacchi 	bool match = false;
45*32002227SRobert Mustacchi 	char inst[128] = { '\0' }, addr[64] = { '\0' };
46*32002227SRobert Mustacchi 	const char *name, *path, *driver;
47*32002227SRobert Mustacchi 	size_t pathlen;
48*32002227SRobert Mustacchi 
49*32002227SRobert Mustacchi 	if (nfilts == 0) {
50*32002227SRobert Mustacchi 		return (true);
51*32002227SRobert Mustacchi 	}
52*32002227SRobert Mustacchi 
53*32002227SRobert Mustacchi 	name = i2c_device_info_name(info);
54*32002227SRobert Mustacchi 	path = i2c_device_info_path(info);
55*32002227SRobert Mustacchi 	pathlen = strlen(path);
56*32002227SRobert Mustacchi 	driver = i2c_device_info_driver(info);
57*32002227SRobert Mustacchi 	if (i2c_device_info_instance(info) != -1 && driver != NULL) {
58*32002227SRobert Mustacchi 		(void) snprintf(inst, sizeof (inst), "%s%d", driver,
59*32002227SRobert Mustacchi 		    i2c_device_info_instance(info));
60*32002227SRobert Mustacchi 	}
61*32002227SRobert Mustacchi 
62*32002227SRobert Mustacchi 	const i2c_addr_t *ia = i2c_device_info_addr_primary(info);
63*32002227SRobert Mustacchi 	if (!i2c_addr_to_string(i2cadm.i2c_hdl, ia, addr, sizeof (addr))) {
64*32002227SRobert Mustacchi 		addr[0] = '\0';
65*32002227SRobert Mustacchi 	}
66*32002227SRobert Mustacchi 
67*32002227SRobert Mustacchi 	/*
68*32002227SRobert Mustacchi 	 * Note, we have to go through all the filters to see if they match as
69*32002227SRobert Mustacchi 	 * someone could have specified something more than once.
70*32002227SRobert Mustacchi 	 */
71*32002227SRobert Mustacchi 	for (int i = 0; i < nfilts; i++) {
72*32002227SRobert Mustacchi 		if (strcmp(filts[i], name) == 0) {
73*32002227SRobert Mustacchi 			used[i] = true;
74*32002227SRobert Mustacchi 			match = true;
75*32002227SRobert Mustacchi 			continue;
76*32002227SRobert Mustacchi 		}
77*32002227SRobert Mustacchi 
78*32002227SRobert Mustacchi 		if (addr[0] != '\0' && strcmp(filts[i], addr) == 0) {
79*32002227SRobert Mustacchi 			used[i] = true;
80*32002227SRobert Mustacchi 			match = true;
81*32002227SRobert Mustacchi 			continue;
82*32002227SRobert Mustacchi 		}
83*32002227SRobert Mustacchi 
84*32002227SRobert Mustacchi 		if (driver != NULL && strcmp(filts[i], driver) == 0) {
85*32002227SRobert Mustacchi 			used[i] = true;
86*32002227SRobert Mustacchi 			match = true;
87*32002227SRobert Mustacchi 			continue;
88*32002227SRobert Mustacchi 		}
89*32002227SRobert Mustacchi 
90*32002227SRobert Mustacchi 		if (inst[0] != '\0' && strcmp(filts[i], inst) == 0) {
91*32002227SRobert Mustacchi 			used[i] = true;
92*32002227SRobert Mustacchi 			match = true;
93*32002227SRobert Mustacchi 			continue;
94*32002227SRobert Mustacchi 		}
95*32002227SRobert Mustacchi 
96*32002227SRobert Mustacchi 		if (strcmp(path, filts[i]) == 0) {
97*32002227SRobert Mustacchi 			used[i] = true;
98*32002227SRobert Mustacchi 			match = true;
99*32002227SRobert Mustacchi 			continue;
100*32002227SRobert Mustacchi 		}
101*32002227SRobert Mustacchi 
102*32002227SRobert Mustacchi 		size_t len = strlen(filts[i]);
103*32002227SRobert Mustacchi 		if (len < pathlen && strncmp(path, filts[i], len) == 0) {
104*32002227SRobert Mustacchi 			used[i] = true;
105*32002227SRobert Mustacchi 			match = true;
106*32002227SRobert Mustacchi 			continue;
107*32002227SRobert Mustacchi 		}
108*32002227SRobert Mustacchi 	}
109*32002227SRobert Mustacchi 
110*32002227SRobert Mustacchi 	return (match);
111*32002227SRobert Mustacchi }
112*32002227SRobert Mustacchi 
113*32002227SRobert Mustacchi static int
i2cadm_device_iter(ofmt_handle_t ofmt,int argc,char * argv[],bool * filts,void (* func)(ofmt_handle_t,const i2c_dev_info_t *))114*32002227SRobert Mustacchi i2cadm_device_iter(ofmt_handle_t ofmt, int argc, char *argv[], bool *filts,
115*32002227SRobert Mustacchi     void (*func)(ofmt_handle_t, const i2c_dev_info_t *))
116*32002227SRobert Mustacchi {
117*32002227SRobert Mustacchi 	int ret = EXIT_SUCCESS;
118*32002227SRobert Mustacchi 	bool print = false;
119*32002227SRobert Mustacchi 	const i2c_dev_disc_t *disc;
120*32002227SRobert Mustacchi 	i2c_dev_iter_t *iter;
121*32002227SRobert Mustacchi 	i2c_iter_t iret;
122*32002227SRobert Mustacchi 
123*32002227SRobert Mustacchi 	if (!i2c_device_discover_init(i2cadm.i2c_hdl, &iter)) {
124*32002227SRobert Mustacchi 		i2cadm_fatal("failed to initialize device discovery");
125*32002227SRobert Mustacchi 	}
126*32002227SRobert Mustacchi 
127*32002227SRobert Mustacchi 	while ((iret = i2c_device_discover_step(iter, &disc)) ==
128*32002227SRobert Mustacchi 	    I2C_ITER_VALID) {
129*32002227SRobert Mustacchi 		i2c_dev_info_t *info;
130*32002227SRobert Mustacchi 
131*32002227SRobert Mustacchi 		if (!i2c_device_info_snap(i2cadm.i2c_hdl,
132*32002227SRobert Mustacchi 		    i2c_device_disc_devi(disc), &info)) {
133*32002227SRobert Mustacchi 			i2cadm_warn("failed to get device information for "
134*32002227SRobert Mustacchi 			    "%s", i2c_device_disc_path(disc));
135*32002227SRobert Mustacchi 			ret = EXIT_FAILURE;
136*32002227SRobert Mustacchi 			continue;
137*32002227SRobert Mustacchi 		}
138*32002227SRobert Mustacchi 
139*32002227SRobert Mustacchi 		if (!i2cadm_device_filt(info, argc, argv, filts)) {
140*32002227SRobert Mustacchi 			i2c_device_info_free(info);
141*32002227SRobert Mustacchi 			continue;
142*32002227SRobert Mustacchi 		}
143*32002227SRobert Mustacchi 
144*32002227SRobert Mustacchi 		func(ofmt, info);
145*32002227SRobert Mustacchi 		i2c_device_info_free(info);
146*32002227SRobert Mustacchi 		print = true;
147*32002227SRobert Mustacchi 	}
148*32002227SRobert Mustacchi 
149*32002227SRobert Mustacchi 	if (iret == I2C_ITER_ERROR) {
150*32002227SRobert Mustacchi 		i2cadm_warn("failed to discover devices");
151*32002227SRobert Mustacchi 		ret = EXIT_FAILURE;
152*32002227SRobert Mustacchi 	}
153*32002227SRobert Mustacchi 
154*32002227SRobert Mustacchi 	for (int i = 0; i < argc; i++) {
155*32002227SRobert Mustacchi 		if (!filts[i]) {
156*32002227SRobert Mustacchi 			warnx("filter '%s' did not match any devices",
157*32002227SRobert Mustacchi 			    argv[i]);
158*32002227SRobert Mustacchi 			ret = EXIT_FAILURE;
159*32002227SRobert Mustacchi 		}
160*32002227SRobert Mustacchi 	}
161*32002227SRobert Mustacchi 
162*32002227SRobert Mustacchi 	if (!print && argc == 0) {
163*32002227SRobert Mustacchi 		warnx("no I2C devices found");
164*32002227SRobert Mustacchi 		ret = EXIT_FAILURE;
165*32002227SRobert Mustacchi 	}
166*32002227SRobert Mustacchi 
167*32002227SRobert Mustacchi 	free(filts);
168*32002227SRobert Mustacchi 	ofmt_close(ofmt);
169*32002227SRobert Mustacchi 	i2c_device_discover_fini(iter);
170*32002227SRobert Mustacchi 
171*32002227SRobert Mustacchi 	return (ret);
172*32002227SRobert Mustacchi }
173*32002227SRobert Mustacchi 
174*32002227SRobert Mustacchi static void
i2cadm_device_addrs_usage(FILE * f)175*32002227SRobert Mustacchi i2cadm_device_addrs_usage(FILE *f)
176*32002227SRobert Mustacchi {
177*32002227SRobert Mustacchi 	(void) fprintf(f, "\ti2cadm device addrs [-H] [-o field,[...] [-p]] "
178*32002227SRobert Mustacchi 	    "[filter]\n");
179*32002227SRobert Mustacchi }
180*32002227SRobert Mustacchi 
181*32002227SRobert Mustacchi static void
i2cadm_device_addrs_help(const char * fmt,...)182*32002227SRobert Mustacchi i2cadm_device_addrs_help(const char *fmt, ...)
183*32002227SRobert Mustacchi {
184*32002227SRobert Mustacchi 	if (fmt != NULL) {
185*32002227SRobert Mustacchi 		va_list ap;
186*32002227SRobert Mustacchi 
187*32002227SRobert Mustacchi 		va_start(ap, fmt);
188*32002227SRobert Mustacchi 		vwarnx(fmt, ap);
189*32002227SRobert Mustacchi 		va_end(ap);
190*32002227SRobert Mustacchi 	}
191*32002227SRobert Mustacchi 
192*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  i2cadm device addrs [-H] "
193*32002227SRobert Mustacchi 	    "[-o field[,...] [-p]] [filters]\n\n");
194*32002227SRobert Mustacchi 	(void) fprintf(stderr, "List addresses assigned to devices and their "
195*32002227SRobert Mustacchi 	    "source. Each <filter> selects\ndevices based upon its address, "
196*32002227SRobert Mustacchi 	    "the device's name, the driver's name, the\ndriver's instance, or "
197*32002227SRobert Mustacchi 	    "the I2C path. Multiple filters are treated as an OR. It\n is an "
198*32002227SRobert Mustacchi 	    "error if a filter isn't used.\n\n"
199*32002227SRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
200*32002227SRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
201*32002227SRobert Mustacchi 	    "\t-p\t\tparseable output (requires -o)\n");
202*32002227SRobert Mustacchi 	(void) fprintf(stderr, "\nThe following fields are supported:\n"
203*32002227SRobert Mustacchi 	    "\tpath\t\tthe device path\n"
204*32002227SRobert Mustacchi 	    "\ttype\t\tthe address's type\n"
205*32002227SRobert Mustacchi 	    "\taddr\t\tthe specific address\n"
206*32002227SRobert Mustacchi 	    "\tsource\tindicates where the address came from\n");
207*32002227SRobert Mustacchi }
208*32002227SRobert Mustacchi 
209*32002227SRobert Mustacchi typedef enum {
210*32002227SRobert Mustacchi 	I2CADM_DEVICE_ADDRS_PATH,
211*32002227SRobert Mustacchi 	I2CADM_DEVICE_ADDRS_TYPE,
212*32002227SRobert Mustacchi 	I2CADM_DEVICE_ADDRS_ADDR,
213*32002227SRobert Mustacchi 	I2CADM_DEVICE_ADDRS_SOURCE
214*32002227SRobert Mustacchi } i2cadm_device_addrs_otype_t;
215*32002227SRobert Mustacchi 
216*32002227SRobert Mustacchi typedef struct i2cadm_device_addrs_ofmt {
217*32002227SRobert Mustacchi 	const i2c_dev_info_t *idoa_info;
218*32002227SRobert Mustacchi 	const i2c_addr_t *idoa_addr;
219*32002227SRobert Mustacchi 	i2c_addr_source_t idoa_source;
220*32002227SRobert Mustacchi } i2cadm_device_addrs_ofmt_t;
221*32002227SRobert Mustacchi 
222*32002227SRobert Mustacchi static boolean_t
i2cadm_device_addrs_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)223*32002227SRobert Mustacchi i2cadm_device_addrs_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
224*32002227SRobert Mustacchi {
225*32002227SRobert Mustacchi 	const i2cadm_device_addrs_ofmt_t *arg = ofarg->ofmt_cbarg;
226*32002227SRobert Mustacchi 	size_t len;
227*32002227SRobert Mustacchi 
228*32002227SRobert Mustacchi 	switch (ofarg->ofmt_id) {
229*32002227SRobert Mustacchi 	case I2CADM_DEVICE_ADDRS_PATH:
230*32002227SRobert Mustacchi 		len = strlcpy(buf, i2c_device_info_path(arg->idoa_info),
231*32002227SRobert Mustacchi 		    buflen);
232*32002227SRobert Mustacchi 		break;
233*32002227SRobert Mustacchi 	case I2CADM_DEVICE_ADDRS_TYPE:
234*32002227SRobert Mustacchi 		if (arg->idoa_addr->ia_type == I2C_ADDR_7BIT) {
235*32002227SRobert Mustacchi 			len = strlcpy(buf, "7-bit", buflen);
236*32002227SRobert Mustacchi 		} else if (arg->idoa_addr->ia_type == I2C_ADDR_10BIT) {
237*32002227SRobert Mustacchi 			len = strlcpy(buf, "10-bit", buflen);
238*32002227SRobert Mustacchi 		} else {
239*32002227SRobert Mustacchi 			len = snprintf(buf, buflen, "unknown (0x%x)",
240*32002227SRobert Mustacchi 			    arg->idoa_addr->ia_type);
241*32002227SRobert Mustacchi 		}
242*32002227SRobert Mustacchi 		break;
243*32002227SRobert Mustacchi 	case I2CADM_DEVICE_ADDRS_ADDR:
244*32002227SRobert Mustacchi 		len = snprintf(buf, buflen, "0x%02x", arg->idoa_addr->ia_addr);
245*32002227SRobert Mustacchi 		break;
246*32002227SRobert Mustacchi 	case I2CADM_DEVICE_ADDRS_SOURCE:
247*32002227SRobert Mustacchi 		switch (arg->idoa_source) {
248*32002227SRobert Mustacchi 		case I2C_ADDR_SOURCE_REG:
249*32002227SRobert Mustacchi 			len = strlcpy(buf, "platform", buflen);
250*32002227SRobert Mustacchi 			break;
251*32002227SRobert Mustacchi 		case I2C_ADDR_SOURCE_CLAIMED:
252*32002227SRobert Mustacchi 			len = strlcpy(buf, "claimed", buflen);
253*32002227SRobert Mustacchi 			break;
254*32002227SRobert Mustacchi 		case I2C_ADDR_SOURCE_SHARED:
255*32002227SRobert Mustacchi 			len = strlcpy(buf, "shared", buflen);
256*32002227SRobert Mustacchi 			break;
257*32002227SRobert Mustacchi 		default:
258*32002227SRobert Mustacchi 			len = snprintf(buf, buflen, "unknown (0x%x)",
259*32002227SRobert Mustacchi 			    arg->idoa_source);
260*32002227SRobert Mustacchi 		}
261*32002227SRobert Mustacchi 		break;
262*32002227SRobert Mustacchi 	default:
263*32002227SRobert Mustacchi 		return (B_FALSE);
264*32002227SRobert Mustacchi 	}
265*32002227SRobert Mustacchi 
266*32002227SRobert Mustacchi 	return (len < buflen);
267*32002227SRobert Mustacchi }
268*32002227SRobert Mustacchi 
269*32002227SRobert Mustacchi static const char *i2cadm_device_addrs_fields = "path,type,addr,source";
270*32002227SRobert Mustacchi static const ofmt_field_t i2cadm_device_addrs_ofmt[] = {
271*32002227SRobert Mustacchi 	{ "PATH", 40, I2CADM_DEVICE_ADDRS_PATH, i2cadm_device_addrs_ofmt_cb },
272*32002227SRobert Mustacchi 	{ "TYPE", 10, I2CADM_DEVICE_ADDRS_TYPE, i2cadm_device_addrs_ofmt_cb },
273*32002227SRobert Mustacchi 	{ "ADDR", 10, I2CADM_DEVICE_ADDRS_ADDR, i2cadm_device_addrs_ofmt_cb },
274*32002227SRobert Mustacchi 	{ "SOURCE", 16, I2CADM_DEVICE_ADDRS_SOURCE,
275*32002227SRobert Mustacchi 	    i2cadm_device_addrs_ofmt_cb },
276*32002227SRobert Mustacchi 	{ NULL, 0, 0, NULL }
277*32002227SRobert Mustacchi };
278*32002227SRobert Mustacchi 
279*32002227SRobert Mustacchi static void
i2cadm_device_addrs_cb(ofmt_handle_t ofmt,const i2c_dev_info_t * info)280*32002227SRobert Mustacchi i2cadm_device_addrs_cb(ofmt_handle_t ofmt, const i2c_dev_info_t *info)
281*32002227SRobert Mustacchi {
282*32002227SRobert Mustacchi 	for (uint32_t i = 0; i < i2c_device_info_naddrs(info); i++) {
283*32002227SRobert Mustacchi 		i2cadm_device_addrs_ofmt_t arg;
284*32002227SRobert Mustacchi 
285*32002227SRobert Mustacchi 		arg.idoa_info = info;
286*32002227SRobert Mustacchi 		arg.idoa_addr = i2c_device_info_addr(info, i);
287*32002227SRobert Mustacchi 		arg.idoa_source = i2c_device_info_addr_source(info, i);
288*32002227SRobert Mustacchi 		ofmt_print(ofmt, &arg);
289*32002227SRobert Mustacchi 	}
290*32002227SRobert Mustacchi }
291*32002227SRobert Mustacchi 
292*32002227SRobert Mustacchi static int
i2cadm_device_addrs(int argc,char * argv[])293*32002227SRobert Mustacchi i2cadm_device_addrs(int argc, char *argv[])
294*32002227SRobert Mustacchi {
295*32002227SRobert Mustacchi 	int c;
296*32002227SRobert Mustacchi 	uint_t flags = 0;
297*32002227SRobert Mustacchi 	boolean_t parse = B_FALSE;
298*32002227SRobert Mustacchi 	const char *fields = NULL;
299*32002227SRobert Mustacchi 	bool *filts = NULL;
300*32002227SRobert Mustacchi 	ofmt_status_t oferr;
301*32002227SRobert Mustacchi 	ofmt_handle_t ofmt;
302*32002227SRobert Mustacchi 
303*32002227SRobert Mustacchi 	while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
304*32002227SRobert Mustacchi 		switch (c) {
305*32002227SRobert Mustacchi 		case 'H':
306*32002227SRobert Mustacchi 			flags |= OFMT_NOHEADER;
307*32002227SRobert Mustacchi 			break;
308*32002227SRobert Mustacchi 		case 'o':
309*32002227SRobert Mustacchi 			fields = optarg;
310*32002227SRobert Mustacchi 			break;
311*32002227SRobert Mustacchi 		case 'p':
312*32002227SRobert Mustacchi 			parse = B_TRUE;
313*32002227SRobert Mustacchi 			flags |= OFMT_PARSABLE;
314*32002227SRobert Mustacchi 			break;
315*32002227SRobert Mustacchi 		case ':':
316*32002227SRobert Mustacchi 			i2cadm_device_addrs_help("option -%c requires an "
317*32002227SRobert Mustacchi 			    "argument", optopt);
318*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
319*32002227SRobert Mustacchi 		case '?':
320*32002227SRobert Mustacchi 			i2cadm_device_addrs_help("unknown option: -%c",
321*32002227SRobert Mustacchi 			    optopt);
322*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
323*32002227SRobert Mustacchi 		}
324*32002227SRobert Mustacchi 	}
325*32002227SRobert Mustacchi 
326*32002227SRobert Mustacchi 	if (parse && fields == NULL) {
327*32002227SRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
328*32002227SRobert Mustacchi 	}
329*32002227SRobert Mustacchi 
330*32002227SRobert Mustacchi 	if (!parse) {
331*32002227SRobert Mustacchi 		flags |= OFMT_WRAP;
332*32002227SRobert Mustacchi 	}
333*32002227SRobert Mustacchi 
334*32002227SRobert Mustacchi 	if (fields == NULL) {
335*32002227SRobert Mustacchi 		fields = i2cadm_device_addrs_fields;
336*32002227SRobert Mustacchi 	}
337*32002227SRobert Mustacchi 
338*32002227SRobert Mustacchi 	argc -= optind;
339*32002227SRobert Mustacchi 	argv += optind;
340*32002227SRobert Mustacchi 
341*32002227SRobert Mustacchi 	if (argc > 0) {
342*32002227SRobert Mustacchi 		filts = calloc(argc, sizeof (bool));
343*32002227SRobert Mustacchi 		if (filts == NULL) {
344*32002227SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
345*32002227SRobert Mustacchi 			    "filter tracking");
346*32002227SRobert Mustacchi 		}
347*32002227SRobert Mustacchi 	}
348*32002227SRobert Mustacchi 
349*32002227SRobert Mustacchi 	oferr = ofmt_open(fields, i2cadm_device_addrs_ofmt, flags, 0, &ofmt);
350*32002227SRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, i2cadm_ofmt_errx, warnx);
351*32002227SRobert Mustacchi 
352*32002227SRobert Mustacchi 	return (i2cadm_device_iter(ofmt, argc, argv, filts,
353*32002227SRobert Mustacchi 	    i2cadm_device_addrs_cb));
354*32002227SRobert Mustacchi }
355*32002227SRobert Mustacchi 
356*32002227SRobert Mustacchi static void
i2cadm_device_list_usage(FILE * f)357*32002227SRobert Mustacchi i2cadm_device_list_usage(FILE *f)
358*32002227SRobert Mustacchi {
359*32002227SRobert Mustacchi 	(void) fprintf(f, "\ti2cadm device list [-H] [-o field,[...] [-p]] "
360*32002227SRobert Mustacchi 	    "[filter]\n");
361*32002227SRobert Mustacchi }
362*32002227SRobert Mustacchi 
363*32002227SRobert Mustacchi static void
i2cadm_device_list_help(const char * fmt,...)364*32002227SRobert Mustacchi i2cadm_device_list_help(const char *fmt, ...)
365*32002227SRobert Mustacchi {
366*32002227SRobert Mustacchi 	if (fmt != NULL) {
367*32002227SRobert Mustacchi 		va_list ap;
368*32002227SRobert Mustacchi 
369*32002227SRobert Mustacchi 		va_start(ap, fmt);
370*32002227SRobert Mustacchi 		vwarnx(fmt, ap);
371*32002227SRobert Mustacchi 		va_end(ap);
372*32002227SRobert Mustacchi 	}
373*32002227SRobert Mustacchi 
374*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  i2cadm device list [-H] "
375*32002227SRobert Mustacchi 	    "[-o field[,...] [-p]] [filter...]\n\n");
376*32002227SRobert Mustacchi 	(void) fprintf(stderr, "List I2C devices in the system. Each <filter> "
377*32002227SRobert Mustacchi 	    "selects devices based upon its\naddress, the device's name, the "
378*32002227SRobert Mustacchi 	    "driver's name, the driver's instance, or the\nI2C path. Multiple "
379*32002227SRobert Mustacchi 	    "filters are treated as an OR. It is an error if a filter\nisn't "
380*32002227SRobert Mustacchi 	    "used.\n\n"
381*32002227SRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
382*32002227SRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
383*32002227SRobert Mustacchi 	    "\t-p\t\tparseable output (requires -o)\n");
384*32002227SRobert Mustacchi 	(void) fprintf(stderr, "\nThe following fields are supported:\n"
385*32002227SRobert Mustacchi 	    "\tname\t\tthe name of the device\n"
386*32002227SRobert Mustacchi 	    "\taddr\t\tthe primary address of the device\n"
387*32002227SRobert Mustacchi 	    "\tinstance\tthe driver instance of the device\n"
388*32002227SRobert Mustacchi 	    "\tpath\t\tthe I2C path of the device\n");
389*32002227SRobert Mustacchi }
390*32002227SRobert Mustacchi 
391*32002227SRobert Mustacchi typedef enum {
392*32002227SRobert Mustacchi 	I2CADM_DEVICE_LIST_NAME,
393*32002227SRobert Mustacchi 	I2CADM_DEVICE_LIST_ADDR,
394*32002227SRobert Mustacchi 	I2CADM_DEVICE_LIST_INSTANCE,
395*32002227SRobert Mustacchi 	I2CADM_DEVICE_LIST_PATH
396*32002227SRobert Mustacchi } i2cadm_device_list_otype_t;
397*32002227SRobert Mustacchi 
398*32002227SRobert Mustacchi static boolean_t
i2cadm_device_list_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)399*32002227SRobert Mustacchi i2cadm_device_list_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
400*32002227SRobert Mustacchi {
401*32002227SRobert Mustacchi 	const i2c_dev_info_t *info = ofarg->ofmt_cbarg;
402*32002227SRobert Mustacchi 	size_t len;
403*32002227SRobert Mustacchi 	const i2c_addr_t *addr;
404*32002227SRobert Mustacchi 
405*32002227SRobert Mustacchi 	switch (ofarg->ofmt_id) {
406*32002227SRobert Mustacchi 	case I2CADM_DEVICE_LIST_NAME:
407*32002227SRobert Mustacchi 		len = strlcpy(buf, i2c_device_info_name(info), buflen);
408*32002227SRobert Mustacchi 		break;
409*32002227SRobert Mustacchi 	case I2CADM_DEVICE_LIST_ADDR:
410*32002227SRobert Mustacchi 		addr = i2c_device_info_addr_primary(info);
411*32002227SRobert Mustacchi 		if (!i2c_addr_to_string(i2cadm.i2c_hdl, addr, buf, buflen)) {
412*32002227SRobert Mustacchi 			return (B_FALSE);
413*32002227SRobert Mustacchi 		}
414*32002227SRobert Mustacchi 
415*32002227SRobert Mustacchi 		return (B_TRUE);
416*32002227SRobert Mustacchi 	case I2CADM_DEVICE_LIST_INSTANCE:
417*32002227SRobert Mustacchi 		if (i2c_device_info_driver(info) != NULL &&
418*32002227SRobert Mustacchi 		    i2c_device_info_instance(info) != -1) {
419*32002227SRobert Mustacchi 			len = snprintf(buf, buflen, "%s%d",
420*32002227SRobert Mustacchi 			    i2c_device_info_driver(info),
421*32002227SRobert Mustacchi 			    i2c_device_info_instance(info));
422*32002227SRobert Mustacchi 		} else {
423*32002227SRobert Mustacchi 			len = strlcpy(buf, "--", buflen);
424*32002227SRobert Mustacchi 		}
425*32002227SRobert Mustacchi 		break;
426*32002227SRobert Mustacchi 	case I2CADM_DEVICE_LIST_PATH:
427*32002227SRobert Mustacchi 		len = strlcpy(buf, i2c_device_info_path(info), buflen);
428*32002227SRobert Mustacchi 		break;
429*32002227SRobert Mustacchi 	default:
430*32002227SRobert Mustacchi 		return (B_FALSE);
431*32002227SRobert Mustacchi 	}
432*32002227SRobert Mustacchi 
433*32002227SRobert Mustacchi 	return (len < buflen);
434*32002227SRobert Mustacchi }
435*32002227SRobert Mustacchi 
436*32002227SRobert Mustacchi static const char *i2cadm_device_list_fields = "name,addr,instance,path";
437*32002227SRobert Mustacchi static const ofmt_field_t i2cadm_device_list_ofmt[] = {
438*32002227SRobert Mustacchi 	{ "NAME", 12, I2CADM_DEVICE_LIST_NAME, i2cadm_device_list_ofmt_cb },
439*32002227SRobert Mustacchi 	{ "ADDR", 12, I2CADM_DEVICE_LIST_ADDR, i2cadm_device_list_ofmt_cb },
440*32002227SRobert Mustacchi 	{ "INSTANCE", 16, I2CADM_DEVICE_LIST_INSTANCE,
441*32002227SRobert Mustacchi 	    i2cadm_device_list_ofmt_cb },
442*32002227SRobert Mustacchi 	{ "PATH", 40, I2CADM_DEVICE_LIST_PATH, i2cadm_device_list_ofmt_cb },
443*32002227SRobert Mustacchi 	{ NULL, 0, 0, NULL }
444*32002227SRobert Mustacchi };
445*32002227SRobert Mustacchi 
446*32002227SRobert Mustacchi static void
i2cadm_device_list_cb(ofmt_handle_t ofmt,const i2c_dev_info_t * info)447*32002227SRobert Mustacchi i2cadm_device_list_cb(ofmt_handle_t ofmt, const i2c_dev_info_t *info)
448*32002227SRobert Mustacchi {
449*32002227SRobert Mustacchi 	ofmt_print(ofmt, (void *)info);
450*32002227SRobert Mustacchi }
451*32002227SRobert Mustacchi 
452*32002227SRobert Mustacchi static int
i2cadm_device_list(int argc,char * argv[])453*32002227SRobert Mustacchi i2cadm_device_list(int argc, char *argv[])
454*32002227SRobert Mustacchi {
455*32002227SRobert Mustacchi 	int c;
456*32002227SRobert Mustacchi 	uint_t flags = 0;
457*32002227SRobert Mustacchi 	boolean_t parse = B_FALSE;
458*32002227SRobert Mustacchi 	const char *fields = NULL;
459*32002227SRobert Mustacchi 	bool *filts = NULL;
460*32002227SRobert Mustacchi 	ofmt_status_t oferr;
461*32002227SRobert Mustacchi 	ofmt_handle_t ofmt;
462*32002227SRobert Mustacchi 
463*32002227SRobert Mustacchi 	while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
464*32002227SRobert Mustacchi 		switch (c) {
465*32002227SRobert Mustacchi 		case 'H':
466*32002227SRobert Mustacchi 			flags |= OFMT_NOHEADER;
467*32002227SRobert Mustacchi 			break;
468*32002227SRobert Mustacchi 		case 'o':
469*32002227SRobert Mustacchi 			fields = optarg;
470*32002227SRobert Mustacchi 			break;
471*32002227SRobert Mustacchi 		case 'p':
472*32002227SRobert Mustacchi 			parse = B_TRUE;
473*32002227SRobert Mustacchi 			flags |= OFMT_PARSABLE;
474*32002227SRobert Mustacchi 			break;
475*32002227SRobert Mustacchi 		case ':':
476*32002227SRobert Mustacchi 			i2cadm_device_list_help("option -%c requires an "
477*32002227SRobert Mustacchi 			    "argument", optopt);
478*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
479*32002227SRobert Mustacchi 		case '?':
480*32002227SRobert Mustacchi 			i2cadm_device_list_help("unknown option: -%c",
481*32002227SRobert Mustacchi 			    optopt);
482*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
483*32002227SRobert Mustacchi 		}
484*32002227SRobert Mustacchi 	}
485*32002227SRobert Mustacchi 
486*32002227SRobert Mustacchi 	if (parse && fields == NULL) {
487*32002227SRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
488*32002227SRobert Mustacchi 	}
489*32002227SRobert Mustacchi 
490*32002227SRobert Mustacchi 	if (!parse) {
491*32002227SRobert Mustacchi 		flags |= OFMT_WRAP;
492*32002227SRobert Mustacchi 	}
493*32002227SRobert Mustacchi 
494*32002227SRobert Mustacchi 	if (fields == NULL) {
495*32002227SRobert Mustacchi 		fields = i2cadm_device_list_fields;
496*32002227SRobert Mustacchi 	}
497*32002227SRobert Mustacchi 
498*32002227SRobert Mustacchi 	argc -= optind;
499*32002227SRobert Mustacchi 	argv += optind;
500*32002227SRobert Mustacchi 
501*32002227SRobert Mustacchi 	if (argc > 0) {
502*32002227SRobert Mustacchi 		filts = calloc(argc, sizeof (bool));
503*32002227SRobert Mustacchi 		if (filts == NULL) {
504*32002227SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
505*32002227SRobert Mustacchi 			    "filter tracking");
506*32002227SRobert Mustacchi 		}
507*32002227SRobert Mustacchi 	}
508*32002227SRobert Mustacchi 
509*32002227SRobert Mustacchi 	oferr = ofmt_open(fields, i2cadm_device_list_ofmt, flags, 0, &ofmt);
510*32002227SRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, i2cadm_ofmt_errx, warnx);
511*32002227SRobert Mustacchi 
512*32002227SRobert Mustacchi 	return (i2cadm_device_iter(ofmt, argc, argv, filts,
513*32002227SRobert Mustacchi 	    i2cadm_device_list_cb));
514*32002227SRobert Mustacchi }
515*32002227SRobert Mustacchi 
516*32002227SRobert Mustacchi static void
i2cadm_device_add_usage(FILE * f)517*32002227SRobert Mustacchi i2cadm_device_add_usage(FILE *f)
518*32002227SRobert Mustacchi {
519*32002227SRobert Mustacchi 	(void) fprintf(f, "\ti2cadm device add [-c compat] port name addr\n");
520*32002227SRobert Mustacchi }
521*32002227SRobert Mustacchi 
522*32002227SRobert Mustacchi static void
i2cadm_device_add_help(const char * fmt,...)523*32002227SRobert Mustacchi i2cadm_device_add_help(const char *fmt, ...)
524*32002227SRobert Mustacchi {
525*32002227SRobert Mustacchi 	if (fmt != NULL) {
526*32002227SRobert Mustacchi 		va_list ap;
527*32002227SRobert Mustacchi 
528*32002227SRobert Mustacchi 		va_start(ap, fmt);
529*32002227SRobert Mustacchi 		vwarnx(fmt, ap);
530*32002227SRobert Mustacchi 		va_end(ap);
531*32002227SRobert Mustacchi 	}
532*32002227SRobert Mustacchi 
533*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  i2cadm device add [-c comapt] "
534*32002227SRobert Mustacchi 	    "port name addr\n\n");
535*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Inform the system of a new I2C device with the "
536*32002227SRobert Mustacchi 	    "specified address. The device\nwill be inserted under the given "
537*32002227SRobert Mustacchi 	    "bus (or multiplexer port if specified). The\naddress must be "
538*32002227SRobert Mustacchi 	    "unique on its multiplexor (if applicable) and bus.\n\n"
539*32002227SRobert Mustacchi 	    "\t-c compat\tAdd the driver compatible entry to the device. This "
540*32002227SRobert Mustacchi 	    "may\n\t\t\tbe specified multiple times. They will be added to "
541*32002227SRobert Mustacchi 	    "the\n\t\t\tdevice in the order specified.\n");
542*32002227SRobert Mustacchi }
543*32002227SRobert Mustacchi 
544*32002227SRobert Mustacchi static int
i2cadm_device_add(int argc,char * argv[])545*32002227SRobert Mustacchi i2cadm_device_add(int argc, char *argv[])
546*32002227SRobert Mustacchi {
547*32002227SRobert Mustacchi 	int c;
548*32002227SRobert Mustacchi 	char **compat = NULL;
549*32002227SRobert Mustacchi 	size_t ncompat = 0, nalloc = 0;
550*32002227SRobert Mustacchi 	i2c_port_t *port;
551*32002227SRobert Mustacchi 	i2c_addr_t addr;
552*32002227SRobert Mustacchi 	i2c_dev_add_req_t *req;
553*32002227SRobert Mustacchi 
554*32002227SRobert Mustacchi 	while ((c = getopt(argc, argv, ":c")) != -1) {
555*32002227SRobert Mustacchi 		switch (c) {
556*32002227SRobert Mustacchi 		case 'c':
557*32002227SRobert Mustacchi 			if (ncompat == nalloc) {
558*32002227SRobert Mustacchi 				nalloc += 8;
559*32002227SRobert Mustacchi 				compat = recallocarray(compat, ncompat, nalloc,
560*32002227SRobert Mustacchi 				    sizeof (char *));
561*32002227SRobert Mustacchi 				if (compat == NULL) {
562*32002227SRobert Mustacchi 					err(EXIT_FAILURE, "failed to allocate "
563*32002227SRobert Mustacchi 					    "memory for %zu compatible array "
564*32002227SRobert Mustacchi 					    "entries", nalloc);
565*32002227SRobert Mustacchi 				}
566*32002227SRobert Mustacchi 			}
567*32002227SRobert Mustacchi 			compat[ncompat] = optarg;
568*32002227SRobert Mustacchi 			ncompat++;
569*32002227SRobert Mustacchi 			break;
570*32002227SRobert Mustacchi 		case ':':
571*32002227SRobert Mustacchi 			i2cadm_device_add_help("option -%c requires an "
572*32002227SRobert Mustacchi 			    "argument", optopt);
573*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
574*32002227SRobert Mustacchi 		case '?':
575*32002227SRobert Mustacchi 			i2cadm_device_add_help("unknown option: -%c", optopt);
576*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
577*32002227SRobert Mustacchi 		}
578*32002227SRobert Mustacchi 	}
579*32002227SRobert Mustacchi 
580*32002227SRobert Mustacchi 	argv += optind;
581*32002227SRobert Mustacchi 	argc -= optind;
582*32002227SRobert Mustacchi 
583*32002227SRobert Mustacchi 	if (argc > 3) {
584*32002227SRobert Mustacchi 		errx(EXIT_USAGE, "encountered extraneous arguments starting "
585*32002227SRobert Mustacchi 		    "with %s", argv[3]);
586*32002227SRobert Mustacchi 	} else if (argc == 0) {
587*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "missing required port path, device name, "
588*32002227SRobert Mustacchi 		    "and device address");
589*32002227SRobert Mustacchi 	} else if (argc == 1) {
590*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "missing required device name and device "
591*32002227SRobert Mustacchi 		    "address");
592*32002227SRobert Mustacchi 	} else if (argc == 2) {
593*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "missing required device address");
594*32002227SRobert Mustacchi 	}
595*32002227SRobert Mustacchi 
596*32002227SRobert Mustacchi 	if (!i2c_port_init_by_path(i2cadm.i2c_hdl, argv[0], &port)) {
597*32002227SRobert Mustacchi 		i2cadm_fatal("failed to parse port path %s", argv[0]);
598*32002227SRobert Mustacchi 	}
599*32002227SRobert Mustacchi 
600*32002227SRobert Mustacchi 	if (!i2c_addr_parse(i2cadm.i2c_hdl, argv[2], &addr)) {
601*32002227SRobert Mustacchi 		i2cadm_fatal("failed to parse address %s", argv[2]);
602*32002227SRobert Mustacchi 	}
603*32002227SRobert Mustacchi 
604*32002227SRobert Mustacchi 	if (!i2c_device_add_req_init(port, &req)) {
605*32002227SRobert Mustacchi 		i2cadm_fatal("failed to initialize device add request");
606*32002227SRobert Mustacchi 	}
607*32002227SRobert Mustacchi 
608*32002227SRobert Mustacchi 	if (!i2c_device_add_req_set_addr(req, &addr)) {
609*32002227SRobert Mustacchi 		i2cadm_fatal("failed to set device address");
610*32002227SRobert Mustacchi 	}
611*32002227SRobert Mustacchi 
612*32002227SRobert Mustacchi 	if (!i2c_device_add_req_set_name(req, argv[1])) {
613*32002227SRobert Mustacchi 		i2cadm_fatal("failed to set device name");
614*32002227SRobert Mustacchi 	}
615*32002227SRobert Mustacchi 
616*32002227SRobert Mustacchi 	if (ncompat > 0 && !i2c_device_add_req_set_compatible(req, compat,
617*32002227SRobert Mustacchi 	    ncompat)) {
618*32002227SRobert Mustacchi 		i2cadm_fatal("failed to set device compatible[]");
619*32002227SRobert Mustacchi 	}
620*32002227SRobert Mustacchi 
621*32002227SRobert Mustacchi 	if (!i2c_device_add_req_exec(req)) {
622*32002227SRobert Mustacchi 		i2cadm_fatal("failed to add device");
623*32002227SRobert Mustacchi 	}
624*32002227SRobert Mustacchi 
625*32002227SRobert Mustacchi 	i2c_device_add_req_fini(req);
626*32002227SRobert Mustacchi 	i2c_port_fini(port);
627*32002227SRobert Mustacchi 	free(compat);
628*32002227SRobert Mustacchi 	return (EXIT_SUCCESS);
629*32002227SRobert Mustacchi }
630*32002227SRobert Mustacchi 
631*32002227SRobert Mustacchi static void
i2cadm_device_remove_usage(FILE * f)632*32002227SRobert Mustacchi i2cadm_device_remove_usage(FILE *f)
633*32002227SRobert Mustacchi {
634*32002227SRobert Mustacchi 	(void) fprintf(f, "\ti2cadm device remove <path>\n");
635*32002227SRobert Mustacchi }
636*32002227SRobert Mustacchi 
637*32002227SRobert Mustacchi static void
i2cadm_device_remove_help(const char * fmt,...)638*32002227SRobert Mustacchi i2cadm_device_remove_help(const char *fmt, ...)
639*32002227SRobert Mustacchi {
640*32002227SRobert Mustacchi 	if (fmt != NULL) {
641*32002227SRobert Mustacchi 		va_list ap;
642*32002227SRobert Mustacchi 
643*32002227SRobert Mustacchi 		va_start(ap, fmt);
644*32002227SRobert Mustacchi 		vwarnx(fmt, ap);
645*32002227SRobert Mustacchi 		va_end(ap);
646*32002227SRobert Mustacchi 	}
647*32002227SRobert Mustacchi 
648*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  i2cadm device remove <path>\n\n");
649*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Remove the I2C device identified by the "
650*32002227SRobert Mustacchi 	    "specified path. If the device is in use,\nthis may "
651*32002227SRobert Mustacchi 	    "fail.\n");
652*32002227SRobert Mustacchi }
653*32002227SRobert Mustacchi 
654*32002227SRobert Mustacchi static int
i2cadm_device_remove(int argc,char * argv[])655*32002227SRobert Mustacchi i2cadm_device_remove(int argc, char *argv[])
656*32002227SRobert Mustacchi {
657*32002227SRobert Mustacchi 	int c;
658*32002227SRobert Mustacchi 	i2c_port_t *port;
659*32002227SRobert Mustacchi 	i2c_dev_info_t *info;
660*32002227SRobert Mustacchi 
661*32002227SRobert Mustacchi 	while ((c = getopt(argc, argv, "")) != -1) {
662*32002227SRobert Mustacchi 		switch (c) {
663*32002227SRobert Mustacchi 		case ':':
664*32002227SRobert Mustacchi 			i2cadm_device_remove_help("option -%c requires an "
665*32002227SRobert Mustacchi 			    "argument", optopt);
666*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
667*32002227SRobert Mustacchi 		case '?':
668*32002227SRobert Mustacchi 			i2cadm_device_remove_help("unknown option: -%c",
669*32002227SRobert Mustacchi 			    optopt);
670*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
671*32002227SRobert Mustacchi 		}
672*32002227SRobert Mustacchi 	}
673*32002227SRobert Mustacchi 
674*32002227SRobert Mustacchi 	argv += optind;
675*32002227SRobert Mustacchi 	argc -= optind;
676*32002227SRobert Mustacchi 
677*32002227SRobert Mustacchi 	if (argc > 1) {
678*32002227SRobert Mustacchi 		errx(EXIT_USAGE, "encountered extraneous arguments starting "
679*32002227SRobert Mustacchi 		    "with %s", argv[1]);
680*32002227SRobert Mustacchi 	} else if (argc == 0) {
681*32002227SRobert Mustacchi 		errx(EXIT_FAILURE, "missing required device path");
682*32002227SRobert Mustacchi 	}
683*32002227SRobert Mustacchi 
684*32002227SRobert Mustacchi 	if (!i2c_port_dev_init_by_path(i2cadm.i2c_hdl, argv[0], false, &port,
685*32002227SRobert Mustacchi 	    &info)) {
686*32002227SRobert Mustacchi 		i2cadm_fatal("failed to parse device path %s", argv[0]);
687*32002227SRobert Mustacchi 	}
688*32002227SRobert Mustacchi 
689*32002227SRobert Mustacchi 	if (!i2c_device_rem(port, i2c_device_info_addr_primary(info))) {
690*32002227SRobert Mustacchi 		i2cadm_fatal("failed to remove device %s", argv[0]);
691*32002227SRobert Mustacchi 	}
692*32002227SRobert Mustacchi 
693*32002227SRobert Mustacchi 	i2c_device_info_free(info);
694*32002227SRobert Mustacchi 	i2c_port_fini(port);
695*32002227SRobert Mustacchi 	return (EXIT_SUCCESS);
696*32002227SRobert Mustacchi }
697*32002227SRobert Mustacchi 
698*32002227SRobert Mustacchi static i2cadm_cmdtab_t i2cadm_device_cmds[] = {
699*32002227SRobert Mustacchi 	{ "list", i2cadm_device_list, i2cadm_device_list_usage },
700*32002227SRobert Mustacchi 	{ "addrs", i2cadm_device_addrs, i2cadm_device_addrs_usage },
701*32002227SRobert Mustacchi 	{ "add", i2cadm_device_add, i2cadm_device_add_usage },
702*32002227SRobert Mustacchi 	{ "remove", i2cadm_device_remove, i2cadm_device_remove_usage }
703*32002227SRobert Mustacchi };
704*32002227SRobert Mustacchi 
705*32002227SRobert Mustacchi int
i2cadm_device(int argc,char * argv[])706*32002227SRobert Mustacchi i2cadm_device(int argc, char *argv[])
707*32002227SRobert Mustacchi {
708*32002227SRobert Mustacchi 	return (i2cadm_walk_tab(i2cadm_device_cmds,
709*32002227SRobert Mustacchi 	    ARRAY_SIZE(i2cadm_device_cmds), argc, argv));
710*32002227SRobert Mustacchi }
711*32002227SRobert Mustacchi 
712*32002227SRobert Mustacchi void
i2cadm_device_usage(FILE * f)713*32002227SRobert Mustacchi i2cadm_device_usage(FILE *f)
714*32002227SRobert Mustacchi {
715*32002227SRobert Mustacchi 	i2cadm_walk_usage(i2cadm_device_cmds, ARRAY_SIZE(i2cadm_device_cmds),
716*32002227SRobert Mustacchi 	    f);
717*32002227SRobert Mustacchi }
718