xref: /illumos-gate/usr/src/test/i2c-tests/tests/libi2c/discovery.c (revision 0cbe48189888d02563dba9c90132ac391ba233b6)
1*0cbe4818SRobert Mustacchi /*
2*0cbe4818SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*0cbe4818SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*0cbe4818SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*0cbe4818SRobert Mustacchi  * 1.0 of the CDDL.
6*0cbe4818SRobert Mustacchi  *
7*0cbe4818SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*0cbe4818SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*0cbe4818SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*0cbe4818SRobert Mustacchi  */
11*0cbe4818SRobert Mustacchi 
12*0cbe4818SRobert Mustacchi /*
13*0cbe4818SRobert Mustacchi  * Copyright 2025 Oxide Computer Company
14*0cbe4818SRobert Mustacchi  */
15*0cbe4818SRobert Mustacchi 
16*0cbe4818SRobert Mustacchi /*
17*0cbe4818SRobert Mustacchi  * Go through our various discovery APIs and make sure that we can find all of
18*0cbe4818SRobert Mustacchi  * the different devices that we expect. This test is designed to operate
19*0cbe4818SRobert Mustacchi  * against the full device complement. Specifically we go through and perform
20*0cbe4818SRobert Mustacchi  * discovery to get the devi, open devices by their devi and then come back and
21*0cbe4818SRobert Mustacchi  * use a path open and verify that we get the same sorts of things.
22*0cbe4818SRobert Mustacchi  */
23*0cbe4818SRobert Mustacchi 
24*0cbe4818SRobert Mustacchi #include <stdlib.h>
25*0cbe4818SRobert Mustacchi #include <err.h>
26*0cbe4818SRobert Mustacchi #include <string.h>
27*0cbe4818SRobert Mustacchi #include <sys/sysmacros.h>
28*0cbe4818SRobert Mustacchi 
29*0cbe4818SRobert Mustacchi #include "libi2c_test_util.h"
30*0cbe4818SRobert Mustacchi 
31*0cbe4818SRobert Mustacchi typedef struct {
32*0cbe4818SRobert Mustacchi 	bool cc_fail;
33*0cbe4818SRobert Mustacchi 	i2c_ctrl_t *cc_i2c;
34*0cbe4818SRobert Mustacchi 	i2c_ctrl_t *cc_smbus;
35*0cbe4818SRobert Mustacchi } ctrl_cb_t;
36*0cbe4818SRobert Mustacchi 
37*0cbe4818SRobert Mustacchi static bool
disc_ctrl_cb(i2c_hdl_t * hdl,const i2c_ctrl_disc_t * disc,void * arg)38*0cbe4818SRobert Mustacchi disc_ctrl_cb(i2c_hdl_t *hdl, const i2c_ctrl_disc_t *disc, void *arg)
39*0cbe4818SRobert Mustacchi {
40*0cbe4818SRobert Mustacchi 	ctrl_cb_t *cb = arg;
41*0cbe4818SRobert Mustacchi 	di_node_t di = i2c_ctrl_disc_devi(disc);
42*0cbe4818SRobert Mustacchi 	const char *name = di_bus_addr(di);
43*0cbe4818SRobert Mustacchi 
44*0cbe4818SRobert Mustacchi 	if (strcmp(name, "i2csim0") == 0) {
45*0cbe4818SRobert Mustacchi 		if (cb->cc_i2c != NULL) {
46*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: discovered i2csim0 a second time!");
47*0cbe4818SRobert Mustacchi 			cb->cc_fail = true;
48*0cbe4818SRobert Mustacchi 		}
49*0cbe4818SRobert Mustacchi 
50*0cbe4818SRobert Mustacchi 		if (!i2c_ctrl_init(hdl, di, &cb->cc_i2c)) {
51*0cbe4818SRobert Mustacchi 			libi2c_test_warn(hdl, "TEST FAILED: failed to "
52*0cbe4818SRobert Mustacchi 			    "initialize i2c_ctrl_t for i2csim0");
53*0cbe4818SRobert Mustacchi 			cb->cc_fail = true;
54*0cbe4818SRobert Mustacchi 		}
55*0cbe4818SRobert Mustacchi 	}
56*0cbe4818SRobert Mustacchi 
57*0cbe4818SRobert Mustacchi 	if (strcmp(name, "smbussim1") == 0) {
58*0cbe4818SRobert Mustacchi 		if (cb->cc_smbus != NULL) {
59*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: discovered smbussim1 a second "
60*0cbe4818SRobert Mustacchi 			    "time!");
61*0cbe4818SRobert Mustacchi 			cb->cc_fail = true;
62*0cbe4818SRobert Mustacchi 		}
63*0cbe4818SRobert Mustacchi 
64*0cbe4818SRobert Mustacchi 		if (!i2c_ctrl_init(hdl, di, &cb->cc_smbus)) {
65*0cbe4818SRobert Mustacchi 			libi2c_test_warn(hdl, "TEST FAILED: failed to "
66*0cbe4818SRobert Mustacchi 			    "initialize i2c_ctrl_t for smbussim1");
67*0cbe4818SRobert Mustacchi 			cb->cc_fail = true;
68*0cbe4818SRobert Mustacchi 		}
69*0cbe4818SRobert Mustacchi 	}
70*0cbe4818SRobert Mustacchi 
71*0cbe4818SRobert Mustacchi 	return (true);
72*0cbe4818SRobert Mustacchi }
73*0cbe4818SRobert Mustacchi 
74*0cbe4818SRobert Mustacchi static bool
disc_ctrl_path(i2c_hdl_t * hdl,i2c_ctrl_t * ctrl,const char * path)75*0cbe4818SRobert Mustacchi disc_ctrl_path(i2c_hdl_t *hdl, i2c_ctrl_t *ctrl, const char *path)
76*0cbe4818SRobert Mustacchi {
77*0cbe4818SRobert Mustacchi 	i2c_ctrl_t *alt;
78*0cbe4818SRobert Mustacchi 	bool ret = true;
79*0cbe4818SRobert Mustacchi 
80*0cbe4818SRobert Mustacchi 	if (!i2c_ctrl_init_by_path(hdl, path, &alt)) {
81*0cbe4818SRobert Mustacchi 		libi2c_test_warn(hdl, "TEST FAILED: failed to initialize "
82*0cbe4818SRobert Mustacchi 		    "controller by path %s", path);
83*0cbe4818SRobert Mustacchi 		return (false);
84*0cbe4818SRobert Mustacchi 	}
85*0cbe4818SRobert Mustacchi 
86*0cbe4818SRobert Mustacchi 	if (strcmp(i2c_ctrl_name(ctrl), i2c_ctrl_name(alt)) != 0) {
87*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: name mismatch on %s: %s vs. %s", path,
88*0cbe4818SRobert Mustacchi 		    i2c_ctrl_name(ctrl), i2c_ctrl_name(alt));
89*0cbe4818SRobert Mustacchi 		ret = false;
90*0cbe4818SRobert Mustacchi 	}
91*0cbe4818SRobert Mustacchi 
92*0cbe4818SRobert Mustacchi 	if (strcmp(i2c_ctrl_path(ctrl), i2c_ctrl_path(alt)) != 0) {
93*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: path mismatch on %s: %s vs. %s", path,
94*0cbe4818SRobert Mustacchi 		    i2c_ctrl_path(ctrl), i2c_ctrl_path(alt));
95*0cbe4818SRobert Mustacchi 		ret = false;
96*0cbe4818SRobert Mustacchi 	}
97*0cbe4818SRobert Mustacchi 
98*0cbe4818SRobert Mustacchi 	if (i2c_ctrl_instance(ctrl) != i2c_ctrl_instance(alt)) {
99*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: instance mismatch on %s: %d vs. %d", path,
100*0cbe4818SRobert Mustacchi 		    i2c_ctrl_instance(ctrl), i2c_ctrl_instance(alt));
101*0cbe4818SRobert Mustacchi 		ret = false;
102*0cbe4818SRobert Mustacchi 	}
103*0cbe4818SRobert Mustacchi 
104*0cbe4818SRobert Mustacchi 	if (i2c_ctrl_nprops(ctrl) != i2c_ctrl_nprops(alt)) {
105*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: nprops mismatch on %s: %u vs. %u", path,
106*0cbe4818SRobert Mustacchi 		    i2c_ctrl_nprops(ctrl), i2c_ctrl_nprops(alt));
107*0cbe4818SRobert Mustacchi 		ret = false;
108*0cbe4818SRobert Mustacchi 	}
109*0cbe4818SRobert Mustacchi 
110*0cbe4818SRobert Mustacchi 	if (ret) {
111*0cbe4818SRobert Mustacchi 		(void) printf("TEST PASSED: Controller %s has the same "
112*0cbe4818SRobert Mustacchi 		    "properties when discovered by devi and path\n", path);
113*0cbe4818SRobert Mustacchi 	}
114*0cbe4818SRobert Mustacchi 	i2c_ctrl_fini(alt);
115*0cbe4818SRobert Mustacchi 	return (ret);
116*0cbe4818SRobert Mustacchi }
117*0cbe4818SRobert Mustacchi 
118*0cbe4818SRobert Mustacchi /*
119*0cbe4818SRobert Mustacchi  * Start by finding and opening the controller for i2csim0 and smbussim1 by
120*0cbe4818SRobert Mustacchi  * their devi based upon controller discovery. Once we have, that come back and
121*0cbe4818SRobert Mustacchi  * use the path based and compare the results.
122*0cbe4818SRobert Mustacchi  */
123*0cbe4818SRobert Mustacchi static bool
disc_ctrls(i2c_hdl_t * hdl)124*0cbe4818SRobert Mustacchi disc_ctrls(i2c_hdl_t *hdl)
125*0cbe4818SRobert Mustacchi {
126*0cbe4818SRobert Mustacchi 	bool ret = true;
127*0cbe4818SRobert Mustacchi 	ctrl_cb_t ctrl_cb;
128*0cbe4818SRobert Mustacchi 
129*0cbe4818SRobert Mustacchi 	(void) memset(&ctrl_cb, 0, sizeof (ctrl_cb));
130*0cbe4818SRobert Mustacchi 	if (!i2c_ctrl_discover(hdl, disc_ctrl_cb, &ctrl_cb)) {
131*0cbe4818SRobert Mustacchi 		libi2c_test_warn(hdl, "TEST FAILED: failed to discover "
132*0cbe4818SRobert Mustacchi 		    "controllers");
133*0cbe4818SRobert Mustacchi 	}
134*0cbe4818SRobert Mustacchi 
135*0cbe4818SRobert Mustacchi 	if (ctrl_cb.cc_fail) {
136*0cbe4818SRobert Mustacchi 		ret = false;
137*0cbe4818SRobert Mustacchi 	}
138*0cbe4818SRobert Mustacchi 
139*0cbe4818SRobert Mustacchi 	if (ctrl_cb.cc_i2c != NULL) {
140*0cbe4818SRobert Mustacchi 		if (!disc_ctrl_path(hdl, ctrl_cb.cc_i2c, "i2csim0"))
141*0cbe4818SRobert Mustacchi 			ret = false;
142*0cbe4818SRobert Mustacchi 		i2c_ctrl_fini(ctrl_cb.cc_i2c);
143*0cbe4818SRobert Mustacchi 	} else {
144*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: failed to discover i2csim0 controller");
145*0cbe4818SRobert Mustacchi 		ret = false;
146*0cbe4818SRobert Mustacchi 	}
147*0cbe4818SRobert Mustacchi 
148*0cbe4818SRobert Mustacchi 	if (ctrl_cb.cc_smbus != NULL) {
149*0cbe4818SRobert Mustacchi 		if (!disc_ctrl_path(hdl, ctrl_cb.cc_smbus, "smbussim1"))
150*0cbe4818SRobert Mustacchi 			ret = false;
151*0cbe4818SRobert Mustacchi 		i2c_ctrl_fini(ctrl_cb.cc_smbus);
152*0cbe4818SRobert Mustacchi 	} else {
153*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: failed to discover smbussim1 controller");
154*0cbe4818SRobert Mustacchi 		ret = false;
155*0cbe4818SRobert Mustacchi 	}
156*0cbe4818SRobert Mustacchi 
157*0cbe4818SRobert Mustacchi 	const char *bad_ctrls[] = { "i2csim0/0", "smbussim1/1", "", "foobar",
158*0cbe4818SRobert Mustacchi 	    "i2csim0/0/0x20", "0x7777" };
159*0cbe4818SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(bad_ctrls); i++) {
160*0cbe4818SRobert Mustacchi 		i2c_ctrl_t *ctrl;
161*0cbe4818SRobert Mustacchi 
162*0cbe4818SRobert Mustacchi 		if (i2c_ctrl_init_by_path(hdl, bad_ctrls[i], &ctrl)) {
163*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: expected path %s to not result "
164*0cbe4818SRobert Mustacchi 			    "in a controller, but we found one!", bad_ctrls[i]);
165*0cbe4818SRobert Mustacchi 			ret = false;
166*0cbe4818SRobert Mustacchi 			i2c_ctrl_fini(ctrl);
167*0cbe4818SRobert Mustacchi 		} else if (i2c_err(hdl) != I2C_ERR_BAD_CONTROLLER) {
168*0cbe4818SRobert Mustacchi 			i2c_err_t e = i2c_err(hdl);
169*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: bad controller %s resulted in "
170*0cbe4818SRobert Mustacchi 			    "error %s (0x%x), but expected "
171*0cbe4818SRobert Mustacchi 			    "I2C_ERR_BAD_CONTROLLER (0x%x)", bad_ctrls[i],
172*0cbe4818SRobert Mustacchi 			    i2c_errtostr(hdl, e), e, I2C_ERR_BAD_CONTROLLER);
173*0cbe4818SRobert Mustacchi 			ret = false;
174*0cbe4818SRobert Mustacchi 		} else {
175*0cbe4818SRobert Mustacchi 			(void) printf("TEST PASSED: successfully failed to "
176*0cbe4818SRobert Mustacchi 			    "open bad controller '%s'\n", bad_ctrls[i]);
177*0cbe4818SRobert Mustacchi 		}
178*0cbe4818SRobert Mustacchi 	}
179*0cbe4818SRobert Mustacchi 
180*0cbe4818SRobert Mustacchi 	return (ret);
181*0cbe4818SRobert Mustacchi }
182*0cbe4818SRobert Mustacchi 
183*0cbe4818SRobert Mustacchi /*
184*0cbe4818SRobert Mustacchi  * Round trip from the devi to a port and get its path and make sure it matches
185*0cbe4818SRobert Mustacchi  * the discovery path.
186*0cbe4818SRobert Mustacchi  */
187*0cbe4818SRobert Mustacchi static bool
disc_port_cb(i2c_hdl_t * hdl,const i2c_port_disc_t * disc,void * arg)188*0cbe4818SRobert Mustacchi disc_port_cb(i2c_hdl_t *hdl, const i2c_port_disc_t *disc, void *arg)
189*0cbe4818SRobert Mustacchi {
190*0cbe4818SRobert Mustacchi 	bool *retp = arg;
191*0cbe4818SRobert Mustacchi 	i2c_port_t *port;
192*0cbe4818SRobert Mustacchi 	const char *dpath = i2c_port_disc_path(disc);
193*0cbe4818SRobert Mustacchi 
194*0cbe4818SRobert Mustacchi 	if (strstr(dpath, "i2csim") == NULL && strstr(dpath, "smbussim") ==
195*0cbe4818SRobert Mustacchi 	    NULL) {
196*0cbe4818SRobert Mustacchi 		return (true);
197*0cbe4818SRobert Mustacchi 	}
198*0cbe4818SRobert Mustacchi 
199*0cbe4818SRobert Mustacchi 	if (!i2c_port_init(hdl, i2c_port_disc_devi(disc), &port)) {
200*0cbe4818SRobert Mustacchi 		libi2c_test_warn(hdl, "failed to open port by devi %s", dpath);
201*0cbe4818SRobert Mustacchi 		*retp = false;
202*0cbe4818SRobert Mustacchi 		return (true);
203*0cbe4818SRobert Mustacchi 	}
204*0cbe4818SRobert Mustacchi 
205*0cbe4818SRobert Mustacchi 	const char *alt_path = i2c_port_path(port);
206*0cbe4818SRobert Mustacchi 	if (strcmp(alt_path, dpath) == 0) {
207*0cbe4818SRobert Mustacchi 		(void) printf("TEST PASSED: port %s has same discovery and "
208*0cbe4818SRobert Mustacchi 		    "i2c_port_t path\n", dpath);
209*0cbe4818SRobert Mustacchi 	} else {
210*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: port %s has different discovery path %s "
211*0cbe4818SRobert Mustacchi 		    "and i2c_port_t path %s", dpath, dpath, alt_path);
212*0cbe4818SRobert Mustacchi 		*retp = false;
213*0cbe4818SRobert Mustacchi 	}
214*0cbe4818SRobert Mustacchi 
215*0cbe4818SRobert Mustacchi 	i2c_port_fini(port);
216*0cbe4818SRobert Mustacchi 	return (true);
217*0cbe4818SRobert Mustacchi }
218*0cbe4818SRobert Mustacchi 
219*0cbe4818SRobert Mustacchi static bool
disc_port_path(i2c_hdl_t * hdl,const char * path,uint32_t portno,i2c_port_type_t type)220*0cbe4818SRobert Mustacchi disc_port_path(i2c_hdl_t *hdl, const char *path, uint32_t portno,
221*0cbe4818SRobert Mustacchi     i2c_port_type_t type)
222*0cbe4818SRobert Mustacchi {
223*0cbe4818SRobert Mustacchi 	bool ret = true;
224*0cbe4818SRobert Mustacchi 	i2c_port_t *port;
225*0cbe4818SRobert Mustacchi 
226*0cbe4818SRobert Mustacchi 	if (i2c_port_init_by_path(hdl, path, &port)) {
227*0cbe4818SRobert Mustacchi 		if (i2c_port_portno(port) != portno) {
228*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: port %s has port number 0x%x, "
229*0cbe4818SRobert Mustacchi 			    "expected 0x%x", path, i2c_port_portno(port),
230*0cbe4818SRobert Mustacchi 			    portno);
231*0cbe4818SRobert Mustacchi 			ret = false;
232*0cbe4818SRobert Mustacchi 		}
233*0cbe4818SRobert Mustacchi 
234*0cbe4818SRobert Mustacchi 		if (i2c_port_type(port) != type) {
235*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: port %s has type 0x%x, expected "
236*0cbe4818SRobert Mustacchi 			    "0x%x", path, i2c_port_type(port), type);
237*0cbe4818SRobert Mustacchi 			ret = false;
238*0cbe4818SRobert Mustacchi 		}
239*0cbe4818SRobert Mustacchi 
240*0cbe4818SRobert Mustacchi 		if (ret) {
241*0cbe4818SRobert Mustacchi 			(void) printf("TEST PASSED: port %s has expected "
242*0cbe4818SRobert Mustacchi 			    "properties\n", path);
243*0cbe4818SRobert Mustacchi 		}
244*0cbe4818SRobert Mustacchi 		i2c_port_fini(port);
245*0cbe4818SRobert Mustacchi 	} else {
246*0cbe4818SRobert Mustacchi 		libi2c_test_warn(hdl, "TEST FAILED: failed to open port %s",
247*0cbe4818SRobert Mustacchi 		    path);
248*0cbe4818SRobert Mustacchi 		ret = false;
249*0cbe4818SRobert Mustacchi 	}
250*0cbe4818SRobert Mustacchi 
251*0cbe4818SRobert Mustacchi 	return (ret);
252*0cbe4818SRobert Mustacchi }
253*0cbe4818SRobert Mustacchi 
254*0cbe4818SRobert Mustacchi static bool
disc_ports(i2c_hdl_t * hdl)255*0cbe4818SRobert Mustacchi disc_ports(i2c_hdl_t *hdl)
256*0cbe4818SRobert Mustacchi {
257*0cbe4818SRobert Mustacchi 	bool ret = true;
258*0cbe4818SRobert Mustacchi 
259*0cbe4818SRobert Mustacchi 	if (!i2c_port_discover(hdl, disc_port_cb, &ret)) {
260*0cbe4818SRobert Mustacchi 		libi2c_test_warn(hdl, "TEST FAILED: failed to walk I2C ports");
261*0cbe4818SRobert Mustacchi 		ret = false;
262*0cbe4818SRobert Mustacchi 	}
263*0cbe4818SRobert Mustacchi 
264*0cbe4818SRobert Mustacchi 	if (!disc_port_path(hdl, "i2csim0/0", 0, I2C_PORT_TYPE_CTRL)) {
265*0cbe4818SRobert Mustacchi 		ret = false;
266*0cbe4818SRobert Mustacchi 	}
267*0cbe4818SRobert Mustacchi 
268*0cbe4818SRobert Mustacchi 	if (!disc_port_path(hdl, "smbussim1/1", 1, I2C_PORT_TYPE_CTRL)) {
269*0cbe4818SRobert Mustacchi 		ret = false;
270*0cbe4818SRobert Mustacchi 	}
271*0cbe4818SRobert Mustacchi 
272*0cbe4818SRobert Mustacchi 	if (!disc_port_path(hdl, "i2csim0/0/0x70/4", 4, I2C_PORT_TYPE_MUX)) {
273*0cbe4818SRobert Mustacchi 		ret = false;
274*0cbe4818SRobert Mustacchi 	}
275*0cbe4818SRobert Mustacchi 
276*0cbe4818SRobert Mustacchi 	if (!disc_port_path(hdl, "i2csim0/0/0x70/0/0x71/3", 3,
277*0cbe4818SRobert Mustacchi 	    I2C_PORT_TYPE_MUX)) {
278*0cbe4818SRobert Mustacchi 		ret = false;
279*0cbe4818SRobert Mustacchi 	}
280*0cbe4818SRobert Mustacchi 
281*0cbe4818SRobert Mustacchi 	const char *bad_ports[] = { "i2csim0", "i2csim0/0/0x20",
282*0cbe4818SRobert Mustacchi 	    "this-does-not-exist", "/", "", "smbussim1/2",
283*0cbe4818SRobert Mustacchi 	    "i2csim0/0/0x70/23" };
284*0cbe4818SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(bad_ports); i++) {
285*0cbe4818SRobert Mustacchi 		i2c_port_t *port;
286*0cbe4818SRobert Mustacchi 
287*0cbe4818SRobert Mustacchi 		if (i2c_port_init_by_path(hdl, bad_ports[i], &port)) {
288*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: expected path %s to not result "
289*0cbe4818SRobert Mustacchi 			    "in a port, but we found one!", bad_ports[i]);
290*0cbe4818SRobert Mustacchi 			ret = false;
291*0cbe4818SRobert Mustacchi 			i2c_port_fini(port);
292*0cbe4818SRobert Mustacchi 		} else if (i2c_err(hdl) != I2C_ERR_BAD_PORT) {
293*0cbe4818SRobert Mustacchi 			i2c_err_t e = i2c_err(hdl);
294*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: bad port %s resulted in error "
295*0cbe4818SRobert Mustacchi 			    "%s (0x%x), but expected I2C_ERR_BAD_PORT (0x%x)",
296*0cbe4818SRobert Mustacchi 			    bad_ports[i], i2c_errtostr(hdl, e), e,
297*0cbe4818SRobert Mustacchi 			    I2C_ERR_BAD_PORT);
298*0cbe4818SRobert Mustacchi 			ret = false;
299*0cbe4818SRobert Mustacchi 		} else {
300*0cbe4818SRobert Mustacchi 			(void) printf("TEST PASSED: successfully failed to "
301*0cbe4818SRobert Mustacchi 			    "open bad port '%s'\n", bad_ports[i]);
302*0cbe4818SRobert Mustacchi 		}
303*0cbe4818SRobert Mustacchi 	}
304*0cbe4818SRobert Mustacchi 
305*0cbe4818SRobert Mustacchi 	return (ret);
306*0cbe4818SRobert Mustacchi }
307*0cbe4818SRobert Mustacchi 
308*0cbe4818SRobert Mustacchi /*
309*0cbe4818SRobert Mustacchi  * Perform basic verification of the i2csim0 muxes which are named after the
310*0cbe4818SRobert Mustacchi  * driver.
311*0cbe4818SRobert Mustacchi  */
312*0cbe4818SRobert Mustacchi static bool
disc_mux_cb(i2c_hdl_t * hdl,const i2c_mux_disc_t * disc,void * arg)313*0cbe4818SRobert Mustacchi disc_mux_cb(i2c_hdl_t *hdl, const i2c_mux_disc_t *disc, void *arg)
314*0cbe4818SRobert Mustacchi {
315*0cbe4818SRobert Mustacchi 	int *retp = arg;
316*0cbe4818SRobert Mustacchi 	const char *path = i2c_mux_disc_path(disc);
317*0cbe4818SRobert Mustacchi 	bool valid = true;
318*0cbe4818SRobert Mustacchi 
319*0cbe4818SRobert Mustacchi 	if (strstr(path, "i2csim0/0/0x70") == NULL)
320*0cbe4818SRobert Mustacchi 		return (true);
321*0cbe4818SRobert Mustacchi 
322*0cbe4818SRobert Mustacchi 	if (i2c_mux_disc_nports(disc) != 8) {
323*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: mux %s has %u ports, not the expected 8",
324*0cbe4818SRobert Mustacchi 		    path, i2c_mux_disc_nports(disc));
325*0cbe4818SRobert Mustacchi 		valid = false;
326*0cbe4818SRobert Mustacchi 	}
327*0cbe4818SRobert Mustacchi 
328*0cbe4818SRobert Mustacchi 	const char *driver = "pca954x";
329*0cbe4818SRobert Mustacchi 	const char *name = i2c_mux_disc_name(disc);
330*0cbe4818SRobert Mustacchi 	if (strncmp(driver, name, strlen(driver)) != 0) {
331*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: mux %s has name %s that doesn't start "
332*0cbe4818SRobert Mustacchi 		    "with %s", path, i2c_mux_disc_name(disc), driver);
333*0cbe4818SRobert Mustacchi 		valid = false;
334*0cbe4818SRobert Mustacchi 	}
335*0cbe4818SRobert Mustacchi 
336*0cbe4818SRobert Mustacchi 	if (valid) {
337*0cbe4818SRobert Mustacchi 		(void) printf("TEST PASSED: i2csim mux %s has expected "
338*0cbe4818SRobert Mustacchi 		    "discovery information\n", path);
339*0cbe4818SRobert Mustacchi 	} else {
340*0cbe4818SRobert Mustacchi 		*retp = EXIT_FAILURE;
341*0cbe4818SRobert Mustacchi 	}
342*0cbe4818SRobert Mustacchi 
343*0cbe4818SRobert Mustacchi 	return (true);
344*0cbe4818SRobert Mustacchi }
345*0cbe4818SRobert Mustacchi 
346*0cbe4818SRobert Mustacchi typedef struct disc_dev {
347*0cbe4818SRobert Mustacchi 	const char *dd_path;
348*0cbe4818SRobert Mustacchi 	const char *dd_name;
349*0cbe4818SRobert Mustacchi 	const char *dd_driver;
350*0cbe4818SRobert Mustacchi 	uint8_t dd_pri;
351*0cbe4818SRobert Mustacchi } disc_dev_t;
352*0cbe4818SRobert Mustacchi 
353*0cbe4818SRobert Mustacchi /*
354*0cbe4818SRobert Mustacchi  * This is a subset of the devices that we expect to exist that we're going to
355*0cbe4818SRobert Mustacchi  * validate against.
356*0cbe4818SRobert Mustacchi  */
357*0cbe4818SRobert Mustacchi static const disc_dev_t disc_devtab[] = {
358*0cbe4818SRobert Mustacchi 	{ "i2csim0/0/0x10", "at24c32", "at24c", 0x10 },
359*0cbe4818SRobert Mustacchi 	{ "i2csim0/0/0x70", "pca9548", "pca954x", 0x70 },
360*0cbe4818SRobert Mustacchi 	{ "i2csim0/0/0x70/0/0x71", "pca9548", "pca954x", 0x71 },
361*0cbe4818SRobert Mustacchi 	{ "i2csim0/0/0x70/2/0x71", "ts5111", "ts511x", 0x71 },
362*0cbe4818SRobert Mustacchi 	{ "i2csim0/0/0x70/2/0x72", "ts5111", "ts511x", 0x72 },
363*0cbe4818SRobert Mustacchi 	{ "i2csim0/0/0x70/3/0x71", "ts5111", "ts511x", 0x71 },
364*0cbe4818SRobert Mustacchi 	{ "i2csim0/0/0x70/3/0x72", "ts5111", "ts511x", 0x72 },
365*0cbe4818SRobert Mustacchi 	{ "i2csim0/0/0x70/0/0x71/7/0x72", "at24c32", "at24c", 0x72 },
366*0cbe4818SRobert Mustacchi };
367*0cbe4818SRobert Mustacchi 
368*0cbe4818SRobert Mustacchi typedef struct {
369*0cbe4818SRobert Mustacchi 	bool dc_err;
370*0cbe4818SRobert Mustacchi 	bool dc_found[ARRAY_SIZE(disc_devtab)];
371*0cbe4818SRobert Mustacchi } disc_cb_t;
372*0cbe4818SRobert Mustacchi 
373*0cbe4818SRobert Mustacchi static bool
disc_devs_cb(i2c_hdl_t * hdl,const i2c_dev_disc_t * disc,void * arg)374*0cbe4818SRobert Mustacchi disc_devs_cb(i2c_hdl_t *hdl, const i2c_dev_disc_t *disc, void *arg)
375*0cbe4818SRobert Mustacchi {
376*0cbe4818SRobert Mustacchi 	const disc_dev_t *dd = NULL;
377*0cbe4818SRobert Mustacchi 	const char *path = i2c_device_disc_path(disc);
378*0cbe4818SRobert Mustacchi 	disc_cb_t *cb = arg;
379*0cbe4818SRobert Mustacchi 	size_t idx;
380*0cbe4818SRobert Mustacchi 
381*0cbe4818SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(disc_devtab); i++) {
382*0cbe4818SRobert Mustacchi 		if (strcmp(disc_devtab[i].dd_path, path) == 0) {
383*0cbe4818SRobert Mustacchi 			dd = &disc_devtab[i];
384*0cbe4818SRobert Mustacchi 			idx = i;
385*0cbe4818SRobert Mustacchi 			break;
386*0cbe4818SRobert Mustacchi 		}
387*0cbe4818SRobert Mustacchi 	}
388*0cbe4818SRobert Mustacchi 
389*0cbe4818SRobert Mustacchi 	if (dd == NULL) {
390*0cbe4818SRobert Mustacchi 		return (true);
391*0cbe4818SRobert Mustacchi 	}
392*0cbe4818SRobert Mustacchi 
393*0cbe4818SRobert Mustacchi 	if (cb->dc_found[idx]) {
394*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: discovered device %s twice", dd->dd_path);
395*0cbe4818SRobert Mustacchi 		cb->dc_err = true;
396*0cbe4818SRobert Mustacchi 		return (true);
397*0cbe4818SRobert Mustacchi 	}
398*0cbe4818SRobert Mustacchi 
399*0cbe4818SRobert Mustacchi 	cb->dc_found[idx] = true;
400*0cbe4818SRobert Mustacchi 	bool valid = true;
401*0cbe4818SRobert Mustacchi 	i2c_dev_info_t *info;
402*0cbe4818SRobert Mustacchi 
403*0cbe4818SRobert Mustacchi 	if (!i2c_device_info_snap(hdl, i2c_device_disc_devi(disc), &info)) {
404*0cbe4818SRobert Mustacchi 		libi2c_test_warn(hdl, "TEST FAILED: failed to get device info "
405*0cbe4818SRobert Mustacchi 		    "for %s", dd->dd_path);
406*0cbe4818SRobert Mustacchi 		cb->dc_err = true;
407*0cbe4818SRobert Mustacchi 		return (true);
408*0cbe4818SRobert Mustacchi 	}
409*0cbe4818SRobert Mustacchi 
410*0cbe4818SRobert Mustacchi 	if (strcmp(i2c_device_info_path(info), dd->dd_path) != 0) {
411*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: device %s has path %s, expected %s",
412*0cbe4818SRobert Mustacchi 		    dd->dd_path, i2c_device_info_path(info), dd->dd_path);
413*0cbe4818SRobert Mustacchi 		cb->dc_err = true;
414*0cbe4818SRobert Mustacchi 		valid = false;
415*0cbe4818SRobert Mustacchi 	}
416*0cbe4818SRobert Mustacchi 
417*0cbe4818SRobert Mustacchi 	if (strcmp(i2c_device_info_name(info), dd->dd_name) != 0) {
418*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: device %s has name %s, expected %s",
419*0cbe4818SRobert Mustacchi 		    dd->dd_path, i2c_device_info_name(info), dd->dd_name);
420*0cbe4818SRobert Mustacchi 		cb->dc_err = true;
421*0cbe4818SRobert Mustacchi 		valid = false;
422*0cbe4818SRobert Mustacchi 	}
423*0cbe4818SRobert Mustacchi 
424*0cbe4818SRobert Mustacchi 	if (strcmp(i2c_device_info_driver(info), dd->dd_driver) != 0) {
425*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: device %s has driver %s, expected %s",
426*0cbe4818SRobert Mustacchi 		    dd->dd_path, i2c_device_info_driver(info), dd->dd_driver);
427*0cbe4818SRobert Mustacchi 		cb->dc_err = true;
428*0cbe4818SRobert Mustacchi 		valid = false;
429*0cbe4818SRobert Mustacchi 	}
430*0cbe4818SRobert Mustacchi 
431*0cbe4818SRobert Mustacchi 	if (i2c_device_info_addr_source(info, 0) != I2C_ADDR_SOURCE_REG) {
432*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: device %s has address source 0x%x, "
433*0cbe4818SRobert Mustacchi 		    "expected 0x%x", dd->dd_path,
434*0cbe4818SRobert Mustacchi 		    i2c_device_info_addr_source(info, 0), I2C_ADDR_SOURCE_REG);
435*0cbe4818SRobert Mustacchi 		cb->dc_err = true;
436*0cbe4818SRobert Mustacchi 		cb->dc_err = true;
437*0cbe4818SRobert Mustacchi 		valid = false;
438*0cbe4818SRobert Mustacchi 	}
439*0cbe4818SRobert Mustacchi 
440*0cbe4818SRobert Mustacchi 	const i2c_addr_t *addr = i2c_device_info_addr_primary(info);
441*0cbe4818SRobert Mustacchi 	if (addr->ia_type != I2C_ADDR_7BIT || addr->ia_addr != dd->dd_pri) {
442*0cbe4818SRobert Mustacchi 		warnx("TEST FAILED: device %s has address 0x%x,0x%x, "
443*0cbe4818SRobert Mustacchi 		    "expected 0x%x,0x%x", dd->dd_path, addr->ia_type,
444*0cbe4818SRobert Mustacchi 		    addr->ia_addr, I2C_ADDR_7BIT, dd->dd_pri);
445*0cbe4818SRobert Mustacchi 		cb->dc_err = true;
446*0cbe4818SRobert Mustacchi 		valid = false;
447*0cbe4818SRobert Mustacchi 	}
448*0cbe4818SRobert Mustacchi 
449*0cbe4818SRobert Mustacchi 	if (valid) {
450*0cbe4818SRobert Mustacchi 		(void) printf("TEST PASSED: device %s information matches "
451*0cbe4818SRobert Mustacchi 		    "table\n", dd->dd_path);
452*0cbe4818SRobert Mustacchi 	}
453*0cbe4818SRobert Mustacchi 	i2c_device_info_free(info);
454*0cbe4818SRobert Mustacchi 	return (true);
455*0cbe4818SRobert Mustacchi }
456*0cbe4818SRobert Mustacchi 
457*0cbe4818SRobert Mustacchi static bool
disc_devs(i2c_hdl_t * hdl)458*0cbe4818SRobert Mustacchi disc_devs(i2c_hdl_t *hdl)
459*0cbe4818SRobert Mustacchi {
460*0cbe4818SRobert Mustacchi 	bool ret = true;
461*0cbe4818SRobert Mustacchi 
462*0cbe4818SRobert Mustacchi 	disc_cb_t cb;
463*0cbe4818SRobert Mustacchi 	(void) memset(&cb, 0, sizeof (cb));
464*0cbe4818SRobert Mustacchi 
465*0cbe4818SRobert Mustacchi 	if (!i2c_device_discover(hdl, disc_devs_cb, &cb)) {
466*0cbe4818SRobert Mustacchi 		libi2c_test_warn(hdl, "TEST FAILED: failed to iterate devices");
467*0cbe4818SRobert Mustacchi 		ret = false;
468*0cbe4818SRobert Mustacchi 	}
469*0cbe4818SRobert Mustacchi 
470*0cbe4818SRobert Mustacchi 	if (cb.dc_err) {
471*0cbe4818SRobert Mustacchi 		ret = false;
472*0cbe4818SRobert Mustacchi 	}
473*0cbe4818SRobert Mustacchi 
474*0cbe4818SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(cb.dc_found); i++) {
475*0cbe4818SRobert Mustacchi 		if (!cb.dc_found[i]) {
476*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: device discovery did not find "
477*0cbe4818SRobert Mustacchi 			    "%s", disc_devtab[i].dd_path);
478*0cbe4818SRobert Mustacchi 			ret = false;
479*0cbe4818SRobert Mustacchi 		}
480*0cbe4818SRobert Mustacchi 	}
481*0cbe4818SRobert Mustacchi 
482*0cbe4818SRobert Mustacchi 	const char *bad_devs[] = { "i2csim0", "", "i2csim0/0", "i2csim0/0/",
483*0cbe4818SRobert Mustacchi 	    "i2csim0/0/0x702", "i2csim0/0/foobar", "i2csim0/0/0x70/0" };
484*0cbe4818SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(bad_devs); i++) {
485*0cbe4818SRobert Mustacchi 		i2c_port_t *port;
486*0cbe4818SRobert Mustacchi 		i2c_dev_info_t *info;
487*0cbe4818SRobert Mustacchi 
488*0cbe4818SRobert Mustacchi 		if (i2c_port_dev_init_by_path(hdl, bad_devs[i], false, &port,
489*0cbe4818SRobert Mustacchi 		    &info)) {
490*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: opened bad device path %s",
491*0cbe4818SRobert Mustacchi 			    bad_devs[i]);
492*0cbe4818SRobert Mustacchi 			i2c_port_fini(port);
493*0cbe4818SRobert Mustacchi 			i2c_device_info_free(info);
494*0cbe4818SRobert Mustacchi 			ret = false;
495*0cbe4818SRobert Mustacchi 		} else if (i2c_err(hdl) != I2C_ERR_BAD_DEVICE) {
496*0cbe4818SRobert Mustacchi 			warnx("TEST FAILED: bad device %s resulted in error "
497*0cbe4818SRobert Mustacchi 			    "%s (0x%x), but expected I2C_ERR_BAD_DEVICE (0x%x)",
498*0cbe4818SRobert Mustacchi 			    bad_devs[i], i2c_errtostr(hdl, i2c_err(hdl)),
499*0cbe4818SRobert Mustacchi 			    i2c_err(hdl), I2C_ERR_BAD_DEVICE);
500*0cbe4818SRobert Mustacchi 			ret = false;
501*0cbe4818SRobert Mustacchi 		} else {
502*0cbe4818SRobert Mustacchi 			(void) printf("TEST PASSED: failed to open bad device "
503*0cbe4818SRobert Mustacchi 			    "%s\n", bad_devs[i]);
504*0cbe4818SRobert Mustacchi 		}
505*0cbe4818SRobert Mustacchi 	}
506*0cbe4818SRobert Mustacchi 
507*0cbe4818SRobert Mustacchi 	return (ret);
508*0cbe4818SRobert Mustacchi }
509*0cbe4818SRobert Mustacchi 
510*0cbe4818SRobert Mustacchi int
main(void)511*0cbe4818SRobert Mustacchi main(void)
512*0cbe4818SRobert Mustacchi {
513*0cbe4818SRobert Mustacchi 	int ret = EXIT_SUCCESS;
514*0cbe4818SRobert Mustacchi 	i2c_hdl_t *hdl = i2c_init();
515*0cbe4818SRobert Mustacchi 	if (hdl == NULL) {
516*0cbe4818SRobert Mustacchi 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to create "
517*0cbe4818SRobert Mustacchi 		    "libi2c handle");
518*0cbe4818SRobert Mustacchi 	}
519*0cbe4818SRobert Mustacchi 
520*0cbe4818SRobert Mustacchi 	if (!disc_ctrls(hdl)) {
521*0cbe4818SRobert Mustacchi 		ret = EXIT_FAILURE;
522*0cbe4818SRobert Mustacchi 	}
523*0cbe4818SRobert Mustacchi 
524*0cbe4818SRobert Mustacchi 	if (!disc_ports(hdl)) {
525*0cbe4818SRobert Mustacchi 		ret = EXIT_FAILURE;
526*0cbe4818SRobert Mustacchi 	}
527*0cbe4818SRobert Mustacchi 
528*0cbe4818SRobert Mustacchi 	if (!i2c_mux_discover(hdl, disc_mux_cb, &ret)) {
529*0cbe4818SRobert Mustacchi 		libi2c_test_warn(hdl, "TEST FAILURE: failed to iterate "
530*0cbe4818SRobert Mustacchi 		    "muxes");
531*0cbe4818SRobert Mustacchi 		ret = EXIT_FAILURE;
532*0cbe4818SRobert Mustacchi 	}
533*0cbe4818SRobert Mustacchi 
534*0cbe4818SRobert Mustacchi 	if (!disc_devs(hdl)) {
535*0cbe4818SRobert Mustacchi 		ret = EXIT_FAILURE;
536*0cbe4818SRobert Mustacchi 	}
537*0cbe4818SRobert Mustacchi 
538*0cbe4818SRobert Mustacchi 	if (ret == EXIT_SUCCESS) {
539*0cbe4818SRobert Mustacchi 		(void) printf("All tests passed successfully\n");
540*0cbe4818SRobert Mustacchi 	}
541*0cbe4818SRobert Mustacchi 	i2c_fini(hdl);
542*0cbe4818SRobert Mustacchi 	return (ret);
543*0cbe4818SRobert Mustacchi }
544