xref: /illumos-gate/usr/src/lib/libi2c/common/libi2c.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  * libi2c, a magical place that deals with everyone's favorite device class to
18*32002227SRobert Mustacchi  * hate.
19*32002227SRobert Mustacchi  */
20*32002227SRobert Mustacchi 
21*32002227SRobert Mustacchi #include <stdlib.h>
22*32002227SRobert Mustacchi #include <ctype.h>
23*32002227SRobert Mustacchi #include <strings.h>
24*32002227SRobert Mustacchi #include <sys/debug.h>
25*32002227SRobert Mustacchi #include <sys/ilstr.h>
26*32002227SRobert Mustacchi #include <fcntl.h>
27*32002227SRobert Mustacchi #include <unistd.h>
28*32002227SRobert Mustacchi #include <sys/obpdefs.h>
29*32002227SRobert Mustacchi 
30*32002227SRobert Mustacchi #include "libi2c_impl.h"
31*32002227SRobert Mustacchi 
32*32002227SRobert Mustacchi void
i2c_fini(i2c_hdl_t * hdl)33*32002227SRobert Mustacchi i2c_fini(i2c_hdl_t *hdl)
34*32002227SRobert Mustacchi {
35*32002227SRobert Mustacchi 	freelocale(hdl->ih_c_loc);
36*32002227SRobert Mustacchi 	(void) close(hdl->ih_devfd);
37*32002227SRobert Mustacchi 	free(hdl);
38*32002227SRobert Mustacchi }
39*32002227SRobert Mustacchi 
40*32002227SRobert Mustacchi i2c_hdl_t *
i2c_init(void)41*32002227SRobert Mustacchi i2c_init(void)
42*32002227SRobert Mustacchi {
43*32002227SRobert Mustacchi 	i2c_hdl_t *hdl;
44*32002227SRobert Mustacchi 
45*32002227SRobert Mustacchi 	hdl = calloc(1, sizeof (i2c_hdl_t));
46*32002227SRobert Mustacchi 	if (hdl == NULL) {
47*32002227SRobert Mustacchi 		return (NULL);
48*32002227SRobert Mustacchi 	}
49*32002227SRobert Mustacchi 
50*32002227SRobert Mustacchi 	hdl->ih_devfd = open("/devices", O_RDONLY | O_DIRECTORY);
51*32002227SRobert Mustacchi 	if (hdl->ih_devfd < 0) {
52*32002227SRobert Mustacchi 		free(hdl);
53*32002227SRobert Mustacchi 		return (NULL);
54*32002227SRobert Mustacchi 	}
55*32002227SRobert Mustacchi 
56*32002227SRobert Mustacchi 	hdl->ih_c_loc = newlocale(LC_ALL_MASK, "C", NULL);
57*32002227SRobert Mustacchi 	return (hdl);
58*32002227SRobert Mustacchi }
59*32002227SRobert Mustacchi 
60*32002227SRobert Mustacchi /*
61*32002227SRobert Mustacchi  * Provide a simple answer as to whether or not an address is a reserved
62*32002227SRobert Mustacchi  * address. This function is a bit awkward as invalid addresses are technically
63*32002227SRobert Mustacchi  * not reserved.
64*32002227SRobert Mustacchi  */
65*32002227SRobert Mustacchi bool
i2c_addr_reserved(const i2c_addr_t * addr)66*32002227SRobert Mustacchi i2c_addr_reserved(const i2c_addr_t *addr)
67*32002227SRobert Mustacchi {
68*32002227SRobert Mustacchi 	switch (addr->ia_type) {
69*32002227SRobert Mustacchi 	case I2C_ADDR_7BIT:
70*32002227SRobert Mustacchi 		if (addr->ia_addr >= (1 << 7)) {
71*32002227SRobert Mustacchi 			return (false);
72*32002227SRobert Mustacchi 		}
73*32002227SRobert Mustacchi 		break;
74*32002227SRobert Mustacchi 	case I2C_ADDR_10BIT:
75*32002227SRobert Mustacchi 		if (addr->ia_addr >= (1 << 10)) {
76*32002227SRobert Mustacchi 			return (false);
77*32002227SRobert Mustacchi 		}
78*32002227SRobert Mustacchi 		break;
79*32002227SRobert Mustacchi 	default:
80*32002227SRobert Mustacchi 		return (false);
81*32002227SRobert Mustacchi 	}
82*32002227SRobert Mustacchi 
83*32002227SRobert Mustacchi 	/*
84*32002227SRobert Mustacchi 	 * Because we've already done a size check up above we know illegal
85*32002227SRobert Mustacchi 	 * 7-bit addresses that are reserved 10-bit addresses will have already
86*32002227SRobert Mustacchi 	 * been checked.
87*32002227SRobert Mustacchi 	 */
88*32002227SRobert Mustacchi 	switch (addr->ia_addr) {
89*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_GEN_CALL:
90*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_C_BUS:
91*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_DIFF_BUS:
92*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_FUTURE:
93*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_HS_0:
94*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_HS_1:
95*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_HS_2:
96*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_HS_3:
97*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_10B_0:
98*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_10B_1:
99*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_10B_2:
100*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_10B_3:
101*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_DID_0:
102*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_DID_1:
103*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_DID_2:
104*32002227SRobert Mustacchi 	case I2C_RSVD_ADDR_DID_3:
105*32002227SRobert Mustacchi 		return (true);
106*32002227SRobert Mustacchi 	default:
107*32002227SRobert Mustacchi 		return (false);
108*32002227SRobert Mustacchi 	}
109*32002227SRobert Mustacchi }
110*32002227SRobert Mustacchi 
111*32002227SRobert Mustacchi bool
i2c_addr_validate(i2c_hdl_t * hdl,const i2c_addr_t * addr)112*32002227SRobert Mustacchi i2c_addr_validate(i2c_hdl_t *hdl, const i2c_addr_t *addr)
113*32002227SRobert Mustacchi {
114*32002227SRobert Mustacchi 	uint16_t max;
115*32002227SRobert Mustacchi 
116*32002227SRobert Mustacchi 	if (addr == NULL) {
117*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
118*32002227SRobert Mustacchi 		    "invalid i2c_addr_t pointer: %p", addr));
119*32002227SRobert Mustacchi 	}
120*32002227SRobert Mustacchi 
121*32002227SRobert Mustacchi 	switch (addr->ia_type) {
122*32002227SRobert Mustacchi 	case I2C_ADDR_7BIT:
123*32002227SRobert Mustacchi 		max = 1 << 7;
124*32002227SRobert Mustacchi 		break;
125*32002227SRobert Mustacchi 	case I2C_ADDR_10BIT:
126*32002227SRobert Mustacchi 		max = 1 << 10;
127*32002227SRobert Mustacchi 		break;
128*32002227SRobert Mustacchi 	default:
129*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_ADDR_TYPE, 0, "invalid "
130*32002227SRobert Mustacchi 		    "address type family 0x%x", addr->ia_type));
131*32002227SRobert Mustacchi 	}
132*32002227SRobert Mustacchi 
133*32002227SRobert Mustacchi 	if (addr->ia_addr >= max) {
134*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_ADDR, 0, "address 0x%x is "
135*32002227SRobert Mustacchi 		    "outside the valid range for the address type: [0x00, "
136*32002227SRobert Mustacchi 		    "0x%02x]", addr->ia_addr, max - 1));
137*32002227SRobert Mustacchi 	}
138*32002227SRobert Mustacchi 
139*32002227SRobert Mustacchi 	return (true);
140*32002227SRobert Mustacchi }
141*32002227SRobert Mustacchi 
142*32002227SRobert Mustacchi /*
143*32002227SRobert Mustacchi  * The set of valid characters for the 'name' and 'compatible' properties comes
144*32002227SRobert Mustacchi  * from IEEE 1275 (which was carried forward into device tree). A name must be
145*32002227SRobert Mustacchi  * at most 31 characters. It is allowed to contain lower case, upper case,
146*32002227SRobert Mustacchi  * numbers, and ",.+-_". We require the first character to be a letter. We check
147*32002227SRobert Mustacchi  * all of this against our copy of the C locale to ensure that a program in a
148*32002227SRobert Mustacchi  * different locale doesn't get a different answer.
149*32002227SRobert Mustacchi  */
150*32002227SRobert Mustacchi CTASSERT(I2C_NAME_MAX == OBP_MAXDRVNAME);
151*32002227SRobert Mustacchi bool
i2c_name_validate(i2c_hdl_t * hdl,const char * name,const char * desc)152*32002227SRobert Mustacchi i2c_name_validate(i2c_hdl_t *hdl, const char *name, const char *desc)
153*32002227SRobert Mustacchi {
154*32002227SRobert Mustacchi 	size_t len;
155*32002227SRobert Mustacchi 
156*32002227SRobert Mustacchi 	if (name == NULL) {
157*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
158*32002227SRobert Mustacchi 		    "invalid %s pointer: %p", desc, name));
159*32002227SRobert Mustacchi 	}
160*32002227SRobert Mustacchi 
161*32002227SRobert Mustacchi 	len = strnlen(name, I2C_NAME_MAX);
162*32002227SRobert Mustacchi 	if (len >= I2C_NAME_MAX) {
163*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_DEV_NAME, 0, "%s exceeds "
164*32002227SRobert Mustacchi 		    "%u character length limit, including NUL", desc,
165*32002227SRobert Mustacchi 		    I2C_NAME_MAX));
166*32002227SRobert Mustacchi 	} else if (len == 0) {
167*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_DEV_NAME, 0, "%s cannot "
168*32002227SRobert Mustacchi 		    "have zero length", desc));
169*32002227SRobert Mustacchi 	}
170*32002227SRobert Mustacchi 
171*32002227SRobert Mustacchi 	if (isalpha_l(name[0], hdl->ih_c_loc) == 0) {
172*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_DEV_NAME, 0, "%s must "
173*32002227SRobert Mustacchi 		    "have an ASCII upper or lowercase first letter: found 0x%x",
174*32002227SRobert Mustacchi 		    desc, name[0]));
175*32002227SRobert Mustacchi 	}
176*32002227SRobert Mustacchi 
177*32002227SRobert Mustacchi 	for (size_t i = 1; i < len; i++) {
178*32002227SRobert Mustacchi 		if (isalpha_l(name[i], hdl->ih_c_loc) ||
179*32002227SRobert Mustacchi 		    isdigit_l(name[i], hdl->ih_c_loc)) {
180*32002227SRobert Mustacchi 			continue;
181*32002227SRobert Mustacchi 		}
182*32002227SRobert Mustacchi 
183*32002227SRobert Mustacchi 		if (name[i] == ',' || name[i] == '.' || name[i] == '+' ||
184*32002227SRobert Mustacchi 		    name[i] == '-' || name[i] == '_') {
185*32002227SRobert Mustacchi 			continue;
186*32002227SRobert Mustacchi 		}
187*32002227SRobert Mustacchi 
188*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_DEV_NAME, 0, "%s character "
189*32002227SRobert Mustacchi 		    "%zu is not from the valid set: found 0x%x", desc, i,
190*32002227SRobert Mustacchi 		    name[i]));
191*32002227SRobert Mustacchi 	}
192*32002227SRobert Mustacchi 
193*32002227SRobert Mustacchi 	return (true);
194*32002227SRobert Mustacchi }
195*32002227SRobert Mustacchi 
196*32002227SRobert Mustacchi i2c_node_type_t
i2c_node_type(di_node_t dn)197*32002227SRobert Mustacchi i2c_node_type(di_node_t dn)
198*32002227SRobert Mustacchi {
199*32002227SRobert Mustacchi 	const char *drv = di_driver_name(dn);
200*32002227SRobert Mustacchi 	char *strs;
201*32002227SRobert Mustacchi 	int nstrs;
202*32002227SRobert Mustacchi 
203*32002227SRobert Mustacchi 	nstrs = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, "device_type",
204*32002227SRobert Mustacchi 	    &strs);
205*32002227SRobert Mustacchi 	if (nstrs == 1 && strcmp(strs, "i2c") == 0) {
206*32002227SRobert Mustacchi 		return (I2C_NODE_T_DEV);
207*32002227SRobert Mustacchi 	}
208*32002227SRobert Mustacchi 
209*32002227SRobert Mustacchi 	if (drv == NULL || strcmp(drv, I2C_NEX_DRV) != 0) {
210*32002227SRobert Mustacchi 		return (I2C_NODE_T_OTHER);
211*32002227SRobert Mustacchi 	}
212*32002227SRobert Mustacchi 
213*32002227SRobert Mustacchi 	nstrs = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, I2C_NEXUS_TYPE_PROP,
214*32002227SRobert Mustacchi 	    &strs);
215*32002227SRobert Mustacchi 	if (nstrs != 1) {
216*32002227SRobert Mustacchi 		return (I2C_NODE_T_OTHER);
217*32002227SRobert Mustacchi 	}
218*32002227SRobert Mustacchi 
219*32002227SRobert Mustacchi 	if (strcmp(strs, I2C_NEXUS_TYPE_PORT) == 0) {
220*32002227SRobert Mustacchi 		return (I2C_NODE_T_PORT);
221*32002227SRobert Mustacchi 	} else if (strcmp(strs, I2C_NEXUS_TYPE_CTRL) == 0) {
222*32002227SRobert Mustacchi 		return (I2C_NODE_T_CTRL);
223*32002227SRobert Mustacchi 	} else if (strcmp(strs, I2C_NEXUS_TYPE_MUX) == 0) {
224*32002227SRobert Mustacchi 		return (I2C_NODE_T_MUX);
225*32002227SRobert Mustacchi 	}
226*32002227SRobert Mustacchi 
227*32002227SRobert Mustacchi 	return (I2C_NODE_T_OTHER);
228*32002227SRobert Mustacchi }
229*32002227SRobert Mustacchi 
230*32002227SRobert Mustacchi /*
231*32002227SRobert Mustacchi  * Given a device node, find the corresponding minor node in its parent port.
232*32002227SRobert Mustacchi  * This node will be named after the kernel form of the device, which is going
233*32002227SRobert Mustacchi  * to be the type,addr aka reg[0],reg[1].
234*32002227SRobert Mustacchi  */
235*32002227SRobert Mustacchi static di_minor_t
i2c_node_minor_device(di_node_t dn)236*32002227SRobert Mustacchi i2c_node_minor_device(di_node_t dn)
237*32002227SRobert Mustacchi {
238*32002227SRobert Mustacchi 	int nreg, *reg;
239*32002227SRobert Mustacchi 	char name[32];
240*32002227SRobert Mustacchi 
241*32002227SRobert Mustacchi 	nreg = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", &reg);
242*32002227SRobert Mustacchi 	if (nreg == 0 || (nreg % 2) != 0) {
243*32002227SRobert Mustacchi 		return (DI_MINOR_NIL);
244*32002227SRobert Mustacchi 	}
245*32002227SRobert Mustacchi 
246*32002227SRobert Mustacchi 	(void) snprintf(name, sizeof (name), "%x,%x", reg[0], reg[1]);
247*32002227SRobert Mustacchi 	dn = di_parent_node(dn);
248*32002227SRobert Mustacchi 	if (i2c_node_type(dn) != I2C_NODE_T_PORT) {
249*32002227SRobert Mustacchi 		return (DI_MINOR_NIL);
250*32002227SRobert Mustacchi 	}
251*32002227SRobert Mustacchi 
252*32002227SRobert Mustacchi 	for (di_minor_t m = di_minor_next(dn, DI_MINOR_NIL); m != DI_MINOR_NIL;
253*32002227SRobert Mustacchi 	    m = di_minor_next(dn, m)) {
254*32002227SRobert Mustacchi 		if (strcmp(di_minor_nodetype(m), DDI_NT_I2C_DEV) == 0 &&
255*32002227SRobert Mustacchi 		    strcmp(di_minor_name(m), name) == 0) {
256*32002227SRobert Mustacchi 			return (m);
257*32002227SRobert Mustacchi 		}
258*32002227SRobert Mustacchi 	}
259*32002227SRobert Mustacchi 
260*32002227SRobert Mustacchi 	return (DI_MINOR_NIL);
261*32002227SRobert Mustacchi }
262*32002227SRobert Mustacchi 
263*32002227SRobert Mustacchi di_minor_t
i2c_node_minor(di_node_t dn)264*32002227SRobert Mustacchi i2c_node_minor(di_node_t dn)
265*32002227SRobert Mustacchi {
266*32002227SRobert Mustacchi 	const char *nt;
267*32002227SRobert Mustacchi 	i2c_node_type_t type = i2c_node_type(dn);
268*32002227SRobert Mustacchi 
269*32002227SRobert Mustacchi 	switch (type) {
270*32002227SRobert Mustacchi 	case I2C_NODE_T_CTRL:
271*32002227SRobert Mustacchi 		nt = DDI_NT_I2C_CTRL;
272*32002227SRobert Mustacchi 		break;
273*32002227SRobert Mustacchi 	case I2C_NODE_T_PORT:
274*32002227SRobert Mustacchi 		nt = DDI_NT_I2C_PORT;
275*32002227SRobert Mustacchi 		break;
276*32002227SRobert Mustacchi 	case I2C_NODE_T_MUX:
277*32002227SRobert Mustacchi 		nt = DDI_NT_I2C_MUX;
278*32002227SRobert Mustacchi 		break;
279*32002227SRobert Mustacchi 	/*
280*32002227SRobert Mustacchi 	 * Device's don't have their control minor under them. The parent port
281*32002227SRobert Mustacchi 	 * has it, so when we need that, change this around to go search the
282*32002227SRobert Mustacchi 	 * parent for it.
283*32002227SRobert Mustacchi 	 */
284*32002227SRobert Mustacchi 	case I2C_NODE_T_DEV:
285*32002227SRobert Mustacchi 		return (i2c_node_minor_device(dn));
286*32002227SRobert Mustacchi 	default:
287*32002227SRobert Mustacchi 		return (DI_MINOR_NIL);
288*32002227SRobert Mustacchi 	}
289*32002227SRobert Mustacchi 
290*32002227SRobert Mustacchi 	for (di_minor_t m = di_minor_next(dn, DI_MINOR_NIL); m != DI_MINOR_NIL;
291*32002227SRobert Mustacchi 	    m = di_minor_next(dn, m)) {
292*32002227SRobert Mustacchi 		if (strcmp(di_minor_nodetype(m), nt) == 0) {
293*32002227SRobert Mustacchi 			return (m);
294*32002227SRobert Mustacchi 		}
295*32002227SRobert Mustacchi 	}
296*32002227SRobert Mustacchi 
297*32002227SRobert Mustacchi 	return (DI_MINOR_NIL);
298*32002227SRobert Mustacchi }
299*32002227SRobert Mustacchi 
300*32002227SRobert Mustacchi bool
i2c_node_is_type(di_node_t dn,i2c_node_type_t type)301*32002227SRobert Mustacchi i2c_node_is_type(di_node_t dn, i2c_node_type_t type)
302*32002227SRobert Mustacchi {
303*32002227SRobert Mustacchi 	return (i2c_node_type(dn) == type);
304*32002227SRobert Mustacchi }
305*32002227SRobert Mustacchi 
306*32002227SRobert Mustacchi 
307*32002227SRobert Mustacchi /*
308*32002227SRobert Mustacchi  * This constructs the named i2c path that can be used to get to the node dn
309*32002227SRobert Mustacchi  * through a series of '/' delineated pieces. The canonical name to use varies
310*32002227SRobert Mustacchi  * based on the node type and stop once we hit a controller:
311*32002227SRobert Mustacchi  *
312*32002227SRobert Mustacchi  *  - controllers: controller name in the di_node_t address
313*32002227SRobert Mustacchi  *  - ports: port name in the di_node_t address
314*32002227SRobert Mustacchi  *  - devices: primary i2c address
315*32002227SRobert Mustacchi  */
316*32002227SRobert Mustacchi bool
i2c_node_to_path(i2c_hdl_t * hdl,di_node_t dn,char * buf,size_t buflen)317*32002227SRobert Mustacchi i2c_node_to_path(i2c_hdl_t *hdl, di_node_t dn, char *buf, size_t buflen)
318*32002227SRobert Mustacchi {
319*32002227SRobert Mustacchi 	ilstr_t ils;
320*32002227SRobert Mustacchi 	bool first = true;
321*32002227SRobert Mustacchi 	i2c_addr_t addr;
322*32002227SRobert Mustacchi 	char addrstr[32];
323*32002227SRobert Mustacchi 
324*32002227SRobert Mustacchi 	ilstr_init_prealloc(&ils, buf, buflen);
325*32002227SRobert Mustacchi 
326*32002227SRobert Mustacchi 	for (;;) {
327*32002227SRobert Mustacchi 		i2c_node_type_t type = i2c_node_type(dn);
328*32002227SRobert Mustacchi 
329*32002227SRobert Mustacchi 		switch (type) {
330*32002227SRobert Mustacchi 		case I2C_NODE_T_CTRL:
331*32002227SRobert Mustacchi 		case I2C_NODE_T_PORT:
332*32002227SRobert Mustacchi 			if (!first) {
333*32002227SRobert Mustacchi 				ilstr_prepend_str(&ils, "/");
334*32002227SRobert Mustacchi 			}
335*32002227SRobert Mustacchi 			ilstr_prepend_str(&ils, di_bus_addr(dn));
336*32002227SRobert Mustacchi 			first = false;
337*32002227SRobert Mustacchi 			break;
338*32002227SRobert Mustacchi 		case I2C_NODE_T_MUX:
339*32002227SRobert Mustacchi 			/*
340*32002227SRobert Mustacchi 			 * The i2cnex that represents a mux today is not used in
341*32002227SRobert Mustacchi 			 * the logical path that we use with humans.
342*32002227SRobert Mustacchi 			 */
343*32002227SRobert Mustacchi 			break;
344*32002227SRobert Mustacchi 		case I2C_NODE_T_DEV:
345*32002227SRobert Mustacchi 			if (!first) {
346*32002227SRobert Mustacchi 				ilstr_prepend_str(&ils, "/");
347*32002227SRobert Mustacchi 			}
348*32002227SRobert Mustacchi 
349*32002227SRobert Mustacchi 			/*
350*32002227SRobert Mustacchi 			 * While it is tempting to use the bus address here, we
351*32002227SRobert Mustacchi 			 * cannot actually assume that a device address is
352*32002227SRobert Mustacchi 			 * valid. A device will only be addressed on the bus if
353*32002227SRobert Mustacchi 			 * a driver is attached to it.
354*32002227SRobert Mustacchi 			 *
355*32002227SRobert Mustacchi 			 * Therefore a device is identified with the primary
356*32002227SRobert Mustacchi 			 * address that it has, e.g. regs[0]. We use the
357*32002227SRobert Mustacchi 			 * somewhat more user firendly form of the address where
358*32002227SRobert Mustacchi 			 * 10-bit addresses have the leading '1,' to indicate
359*32002227SRobert Mustacchi 			 * the class, but 7-bit do not. As in practice that's
360*32002227SRobert Mustacchi 			 * what we'll be dealing with 99% of the time.
361*32002227SRobert Mustacchi 			 */
362*32002227SRobert Mustacchi 			if (!i2c_reg_to_addr(hdl, dn, &addr, 0)) {
363*32002227SRobert Mustacchi 				return (false);
364*32002227SRobert Mustacchi 			}
365*32002227SRobert Mustacchi 
366*32002227SRobert Mustacchi 			VERIFY(i2c_addr_to_string(hdl, &addr, addrstr,
367*32002227SRobert Mustacchi 			    sizeof (addrstr)));
368*32002227SRobert Mustacchi 			ilstr_prepend_str(&ils, addrstr);
369*32002227SRobert Mustacchi 			first = false;
370*32002227SRobert Mustacchi 			break;
371*32002227SRobert Mustacchi 		default:
372*32002227SRobert Mustacchi 			return (i2c_error(hdl, I2C_ERR_INTERNAL, 0,
373*32002227SRobert Mustacchi 			    "encountered unknown node type constructing path: "
374*32002227SRobert Mustacchi 			    "0x%x", type));
375*32002227SRobert Mustacchi 		}
376*32002227SRobert Mustacchi 
377*32002227SRobert Mustacchi 		/*
378*32002227SRobert Mustacchi 		 * If we've hit a controller we're done. However, look out in
379*32002227SRobert Mustacchi 		 * case we haven't and make sure we have a parent before
380*32002227SRobert Mustacchi 		 * continuing.
381*32002227SRobert Mustacchi 		 */
382*32002227SRobert Mustacchi 		if (type == I2C_NODE_T_CTRL)
383*32002227SRobert Mustacchi 			break;
384*32002227SRobert Mustacchi 
385*32002227SRobert Mustacchi 		dn = di_parent_node(dn);
386*32002227SRobert Mustacchi 		if (dn == DI_NODE_NIL)
387*32002227SRobert Mustacchi 			break;
388*32002227SRobert Mustacchi 	}
389*32002227SRobert Mustacchi 
390*32002227SRobert Mustacchi 	if (ilstr_errno(&ils) != ILSTR_ERROR_OK) {
391*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "failed to "
392*32002227SRobert Mustacchi 		    "construct string for node %s: %s", di_node_name(dn),
393*32002227SRobert Mustacchi 		    ilstr_errstr(&ils)));
394*32002227SRobert Mustacchi 	}
395*32002227SRobert Mustacchi 
396*32002227SRobert Mustacchi 	return (true);
397*32002227SRobert Mustacchi }
398*32002227SRobert Mustacchi 
399*32002227SRobert Mustacchi /*
400*32002227SRobert Mustacchi  * Parse the kernel's I2C device address style, <type>,<address>. The only
401*32002227SRobert Mustacchi  * thing assumed about str is that it is null terminated. The kernel integers
402*32002227SRobert Mustacchi  * for type and address are always in hex regardless of whether or not they
403*32002227SRobert Mustacchi  * have a leading 0x.
404*32002227SRobert Mustacchi  */
405*32002227SRobert Mustacchi bool
i2c_kernel_address_parse(i2c_hdl_t * hdl,const char * str,i2c_addr_t * addr)406*32002227SRobert Mustacchi i2c_kernel_address_parse(i2c_hdl_t *hdl, const char *str, i2c_addr_t *addr)
407*32002227SRobert Mustacchi {
408*32002227SRobert Mustacchi 	char *eptr;
409*32002227SRobert Mustacchi 	unsigned long ul;
410*32002227SRobert Mustacchi 
411*32002227SRobert Mustacchi 	errno = 0;
412*32002227SRobert Mustacchi 	ul = strtoul(str, &eptr, 16);
413*32002227SRobert Mustacchi 	if (errno != 0 || *eptr != ',') {
414*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "kernel string %s "
415*32002227SRobert Mustacchi 		    "did not have a valid leading type", str));
416*32002227SRobert Mustacchi 	}
417*32002227SRobert Mustacchi 
418*32002227SRobert Mustacchi 	if (ul == I2C_ADDR_7BIT) {
419*32002227SRobert Mustacchi 		addr->ia_type = I2C_ADDR_7BIT;
420*32002227SRobert Mustacchi 	} else if (ul == I2C_ADDR_10BIT) {
421*32002227SRobert Mustacchi 		addr->ia_type = I2C_ADDR_10BIT;
422*32002227SRobert Mustacchi 	} else {
423*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "kernel string %s "
424*32002227SRobert Mustacchi 		    "did not have a valid type, found 0x%lx", str, ul));
425*32002227SRobert Mustacchi 	}
426*32002227SRobert Mustacchi 
427*32002227SRobert Mustacchi 	errno = 0;
428*32002227SRobert Mustacchi 	ul = strtoul(eptr + 1, &eptr, 16);
429*32002227SRobert Mustacchi 	if (errno != 0 || *eptr != '\0') {
430*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "kernel string %s "
431*32002227SRobert Mustacchi 		    "did not have a valid address", str));
432*32002227SRobert Mustacchi 	}
433*32002227SRobert Mustacchi 
434*32002227SRobert Mustacchi 	if ((addr->ia_type == I2C_ADDR_7BIT && ul >= 1 << 7) ||
435*32002227SRobert Mustacchi 	    (addr->ia_type == I2C_ADDR_10BIT && ul >= 1 << 10)) {
436*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "kernel string %s "
437*32002227SRobert Mustacchi 		    "address 0x%lx is too large for type", str, ul));
438*32002227SRobert Mustacchi 	}
439*32002227SRobert Mustacchi 
440*32002227SRobert Mustacchi 	addr->ia_addr = (uint16_t)ul;
441*32002227SRobert Mustacchi 	return (true);
442*32002227SRobert Mustacchi }
443*32002227SRobert Mustacchi 
444*32002227SRobert Mustacchi /*
445*32002227SRobert Mustacchi  * Parse a user address as compared to a kernel address. The main difference
446*32002227SRobert Mustacchi  * here is that the user address does not use a prefix for the 7-bit addresses
447*32002227SRobert Mustacchi  * and the 10-bit addresses use the "10b," prefix.
448*32002227SRobert Mustacchi  */
449*32002227SRobert Mustacchi bool
i2c_addr_parse(i2c_hdl_t * hdl,const char * buf,i2c_addr_t * addr)450*32002227SRobert Mustacchi i2c_addr_parse(i2c_hdl_t *hdl, const char *buf, i2c_addr_t *addr)
451*32002227SRobert Mustacchi {
452*32002227SRobert Mustacchi 	char *eptr;
453*32002227SRobert Mustacchi 	unsigned long ul;
454*32002227SRobert Mustacchi 	const char *comma;
455*32002227SRobert Mustacchi 	uint16_t max;
456*32002227SRobert Mustacchi 
457*32002227SRobert Mustacchi 	if (buf == NULL) {
458*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
459*32002227SRobert Mustacchi 		    "invalid address string pointer: %p", buf));
460*32002227SRobert Mustacchi 	}
461*32002227SRobert Mustacchi 
462*32002227SRobert Mustacchi 	if (addr == NULL) {
463*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
464*32002227SRobert Mustacchi 		    "invalid i2c_addr_t pointer: %p", addr));
465*32002227SRobert Mustacchi 	}
466*32002227SRobert Mustacchi 
467*32002227SRobert Mustacchi 	comma = strchr(buf, ',');
468*32002227SRobert Mustacchi 	if (comma != NULL) {
469*32002227SRobert Mustacchi 		size_t len = (uintptr_t)comma - (uintptr_t)buf;
470*32002227SRobert Mustacchi 		if (len != 3 || strncmp("10b", buf, len) != 0) {
471*32002227SRobert Mustacchi 			return (i2c_error(hdl, I2C_ERR_BAD_ADDR_TYPE, 0,
472*32002227SRobert Mustacchi 			    "found invalid address type on %s", buf));
473*32002227SRobert Mustacchi 		}
474*32002227SRobert Mustacchi 		addr->ia_type = I2C_ADDR_10BIT;
475*32002227SRobert Mustacchi 		buf = comma + 1;
476*32002227SRobert Mustacchi 		max = 1 << 10;
477*32002227SRobert Mustacchi 	} else {
478*32002227SRobert Mustacchi 		addr->ia_type = I2C_ADDR_7BIT;
479*32002227SRobert Mustacchi 		max = 1 << 7;
480*32002227SRobert Mustacchi 	}
481*32002227SRobert Mustacchi 
482*32002227SRobert Mustacchi 	errno = 0;
483*32002227SRobert Mustacchi 	ul = strtoul(buf, &eptr, 0);
484*32002227SRobert Mustacchi 	if (errno != 0 || *eptr != '\0') {
485*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_ADDR, 0, "address %s could "
486*32002227SRobert Mustacchi 		    "not be parsed", buf));
487*32002227SRobert Mustacchi 	}
488*32002227SRobert Mustacchi 
489*32002227SRobert Mustacchi 	if (ul >= max) {
490*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_ADDR, 0, "address 0x%lx is "
491*32002227SRobert Mustacchi 		    "outside the valid range for the address type: [0x00, "
492*32002227SRobert Mustacchi 		    "0x%02x]", ul, max - 1));
493*32002227SRobert Mustacchi 	}
494*32002227SRobert Mustacchi 
495*32002227SRobert Mustacchi 	addr->ia_addr = (uint16_t)ul;
496*32002227SRobert Mustacchi 	return (true);
497*32002227SRobert Mustacchi }
498*32002227SRobert Mustacchi 
499*32002227SRobert Mustacchi bool
i2c_addr_to_string(i2c_hdl_t * hdl,const i2c_addr_t * addr,char * buf,size_t len)500*32002227SRobert Mustacchi i2c_addr_to_string(i2c_hdl_t *hdl, const i2c_addr_t *addr, char *buf,
501*32002227SRobert Mustacchi     size_t len)
502*32002227SRobert Mustacchi {
503*32002227SRobert Mustacchi 	size_t ret;
504*32002227SRobert Mustacchi 
505*32002227SRobert Mustacchi 	if (buf == NULL) {
506*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
507*32002227SRobert Mustacchi 		    "invalid address string pointer: %p", buf));
508*32002227SRobert Mustacchi 	}
509*32002227SRobert Mustacchi 
510*32002227SRobert Mustacchi 	if (addr == NULL) {
511*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
512*32002227SRobert Mustacchi 		    "invalid i2c_addr_t pointer: %p", addr));
513*32002227SRobert Mustacchi 	}
514*32002227SRobert Mustacchi 
515*32002227SRobert Mustacchi 	if (!i2c_addr_validate(hdl, addr)) {
516*32002227SRobert Mustacchi 		return (false);
517*32002227SRobert Mustacchi 	}
518*32002227SRobert Mustacchi 
519*32002227SRobert Mustacchi 	if (addr->ia_type == I2C_ADDR_10BIT) {
520*32002227SRobert Mustacchi 		ret = snprintf(buf, len, "10b,0x%03x", addr->ia_addr);
521*32002227SRobert Mustacchi 	} else {
522*32002227SRobert Mustacchi 		ret = snprintf(buf, len, "0x%02x", addr->ia_addr);
523*32002227SRobert Mustacchi 	}
524*32002227SRobert Mustacchi 	if (ret >= len) {
525*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BUF_TOO_SMALL, 0, "output "
526*32002227SRobert Mustacchi 		    "buffer is too small: need %zu bytes, have %zu", ret,
527*32002227SRobert Mustacchi 		    len));
528*32002227SRobert Mustacchi 	}
529*32002227SRobert Mustacchi 
530*32002227SRobert Mustacchi 	return (true);
531*32002227SRobert Mustacchi }
532*32002227SRobert Mustacchi 
533*32002227SRobert Mustacchi /*
534*32002227SRobert Mustacchi  * Convert the specified index for a device into an address.
535*32002227SRobert Mustacchi  */
536*32002227SRobert Mustacchi bool
i2c_reg_to_addr(i2c_hdl_t * hdl,di_node_t dn,i2c_addr_t * addr,uint32_t n)537*32002227SRobert Mustacchi i2c_reg_to_addr(i2c_hdl_t *hdl, di_node_t dn, i2c_addr_t *addr, uint32_t n)
538*32002227SRobert Mustacchi {
539*32002227SRobert Mustacchi 	int nreg, *reg;
540*32002227SRobert Mustacchi 	uint32_t type_idx = n * 2;
541*32002227SRobert Mustacchi 	uint32_t addr_idx = n * 2 + 1;
542*32002227SRobert Mustacchi 
543*32002227SRobert Mustacchi 	nreg = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", &reg);
544*32002227SRobert Mustacchi 	if (nreg == 0 || (nreg % 2) != 0) {
545*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "device %s@%s "
546*32002227SRobert Mustacchi 		    "does not have a valid i2c reg[] property",
547*32002227SRobert Mustacchi 		    di_node_name(dn), di_bus_addr(dn)));
548*32002227SRobert Mustacchi 	}
549*32002227SRobert Mustacchi 
550*32002227SRobert Mustacchi 	if (addr_idx >= nreg) {
551*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "device %s@%s "
552*32002227SRobert Mustacchi 		    "does not have a valid i2c reg[] property",
553*32002227SRobert Mustacchi 		    di_node_name(dn), di_bus_addr(dn)));
554*32002227SRobert Mustacchi 	}
555*32002227SRobert Mustacchi 
556*32002227SRobert Mustacchi 	if (reg[type_idx] == I2C_ADDR_7BIT) {
557*32002227SRobert Mustacchi 		addr->ia_type = I2C_ADDR_7BIT;
558*32002227SRobert Mustacchi 	} else if (reg[type_idx] == I2C_ADDR_10BIT) {
559*32002227SRobert Mustacchi 		addr->ia_type = I2C_ADDR_10BIT;
560*32002227SRobert Mustacchi 	} else {
561*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "device %s@%s "
562*32002227SRobert Mustacchi 		    "does not have a valid i2c address type, found 0x%x",
563*32002227SRobert Mustacchi 		    di_node_name(dn), di_bus_addr(dn), reg[type_idx]));
564*32002227SRobert Mustacchi 	}
565*32002227SRobert Mustacchi 
566*32002227SRobert Mustacchi 	if ((addr->ia_type == I2C_ADDR_7BIT && reg[addr_idx] >= 1 << 7) ||
567*32002227SRobert Mustacchi 	    (addr->ia_type == I2C_ADDR_10BIT && reg[addr_idx] >= 1 << 10)) {
568*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_INTERNAL, 0, "device %s@%s "
569*32002227SRobert Mustacchi 		    "address 0x%x is too large for type", di_node_name(dn),
570*32002227SRobert Mustacchi 		    di_bus_addr(dn), reg[addr_idx]));
571*32002227SRobert Mustacchi 	}
572*32002227SRobert Mustacchi 
573*32002227SRobert Mustacchi 	addr->ia_addr = (uint16_t)reg[1];
574*32002227SRobert Mustacchi 
575*32002227SRobert Mustacchi 	return (true);
576*32002227SRobert Mustacchi }
577*32002227SRobert Mustacchi 
578*32002227SRobert Mustacchi bool
i2c_addr_equal(const i2c_addr_t * a,const i2c_addr_t * b)579*32002227SRobert Mustacchi i2c_addr_equal(const i2c_addr_t *a, const i2c_addr_t *b)
580*32002227SRobert Mustacchi {
581*32002227SRobert Mustacchi 	return (a->ia_type == b->ia_type && a->ia_addr == b->ia_addr);
582*32002227SRobert Mustacchi }
583*32002227SRobert Mustacchi 
584*32002227SRobert Mustacchi di_node_t
i2c_path_find_ctrl(di_node_t root,const char * name)585*32002227SRobert Mustacchi i2c_path_find_ctrl(di_node_t root, const char *name)
586*32002227SRobert Mustacchi {
587*32002227SRobert Mustacchi 	for (di_node_t di = di_drv_first_node(I2C_NEX_DRV, root); di != NULL;
588*32002227SRobert Mustacchi 	    di = di_drv_next_node(di)) {
589*32002227SRobert Mustacchi 		if (!i2c_node_is_type(di, I2C_NODE_T_CTRL)) {
590*32002227SRobert Mustacchi 			continue;
591*32002227SRobert Mustacchi 		}
592*32002227SRobert Mustacchi 
593*32002227SRobert Mustacchi 		if (strcmp(name, di_bus_addr(di)) == 0) {
594*32002227SRobert Mustacchi 			return (di);
595*32002227SRobert Mustacchi 		}
596*32002227SRobert Mustacchi 	}
597*32002227SRobert Mustacchi 
598*32002227SRobert Mustacchi 	return (DI_NODE_NIL);
599*32002227SRobert Mustacchi }
600*32002227SRobert Mustacchi 
601*32002227SRobert Mustacchi di_node_t
i2c_path_find_mux(di_node_t dev)602*32002227SRobert Mustacchi i2c_path_find_mux(di_node_t dev)
603*32002227SRobert Mustacchi {
604*32002227SRobert Mustacchi 	for (di_node_t dn = di_child_node(dev); dn != NULL;
605*32002227SRobert Mustacchi 	    dn = di_sibling_node(dn)) {
606*32002227SRobert Mustacchi 		if (i2c_node_type(dn) == I2C_NODE_T_MUX) {
607*32002227SRobert Mustacchi 			return (dn);
608*32002227SRobert Mustacchi 		}
609*32002227SRobert Mustacchi 	}
610*32002227SRobert Mustacchi 
611*32002227SRobert Mustacchi 	return (DI_NODE_NIL);
612*32002227SRobert Mustacchi }
613*32002227SRobert Mustacchi 
614*32002227SRobert Mustacchi di_node_t
i2c_path_find_port(di_node_t parent,const char * name)615*32002227SRobert Mustacchi i2c_path_find_port(di_node_t parent, const char *name)
616*32002227SRobert Mustacchi {
617*32002227SRobert Mustacchi 	for (di_node_t dn = di_child_node(parent); dn != NULL;
618*32002227SRobert Mustacchi 	    dn = di_sibling_node(dn)) {
619*32002227SRobert Mustacchi 		if (!i2c_node_is_type(dn, I2C_NODE_T_PORT)) {
620*32002227SRobert Mustacchi 			continue;
621*32002227SRobert Mustacchi 		}
622*32002227SRobert Mustacchi 
623*32002227SRobert Mustacchi 		if (strcmp(di_bus_addr(dn), name) == 0) {
624*32002227SRobert Mustacchi 			return (dn);
625*32002227SRobert Mustacchi 		}
626*32002227SRobert Mustacchi 	}
627*32002227SRobert Mustacchi 
628*32002227SRobert Mustacchi 	return (DI_NODE_NIL);
629*32002227SRobert Mustacchi }
630*32002227SRobert Mustacchi 
631*32002227SRobert Mustacchi /*
632*32002227SRobert Mustacchi  * When parsing a device, there are three different options that we accept:
633*32002227SRobert Mustacchi  *
634*32002227SRobert Mustacchi  *  - The device's name@address
635*32002227SRobert Mustacchi  *  - The device's address
636*32002227SRobert Mustacchi  *  - The device's driver and instance (e.g. spd511x2)
637*32002227SRobert Mustacchi  *
638*32002227SRobert Mustacchi  * The address is always reg[0] because the aactual node address may not exist
639*32002227SRobert Mustacchi  * at this time. Similarly, we cannot assume that a driver is bound and attached
640*32002227SRobert Mustacchi  * to the node.
641*32002227SRobert Mustacchi  */
642*32002227SRobert Mustacchi di_node_t
i2c_path_find_device(i2c_hdl_t * hdl,di_node_t port,const char * name)643*32002227SRobert Mustacchi i2c_path_find_device(i2c_hdl_t *hdl, di_node_t port, const char *name)
644*32002227SRobert Mustacchi {
645*32002227SRobert Mustacchi 	for (di_node_t dn = di_child_node(port); dn != NULL;
646*32002227SRobert Mustacchi 	    dn = di_sibling_node(dn)) {
647*32002227SRobert Mustacchi 		i2c_addr_t daddr;
648*32002227SRobert Mustacchi 		char daddrstr[32];
649*32002227SRobert Mustacchi 
650*32002227SRobert Mustacchi 		if (i2c_node_type(dn) != I2C_NODE_T_DEV) {
651*32002227SRobert Mustacchi 			continue;
652*32002227SRobert Mustacchi 		}
653*32002227SRobert Mustacchi 
654*32002227SRobert Mustacchi 		if (!i2c_reg_to_addr(hdl, dn, &daddr, 0)) {
655*32002227SRobert Mustacchi 			continue;
656*32002227SRobert Mustacchi 		}
657*32002227SRobert Mustacchi 
658*32002227SRobert Mustacchi 		if (!i2c_addr_to_string(hdl, &daddr, daddrstr,
659*32002227SRobert Mustacchi 		    sizeof (daddrstr))) {
660*32002227SRobert Mustacchi 			continue;
661*32002227SRobert Mustacchi 		}
662*32002227SRobert Mustacchi 
663*32002227SRobert Mustacchi 		/*
664*32002227SRobert Mustacchi 		 * Always check if we match on the converted address.
665*32002227SRobert Mustacchi 		 */
666*32002227SRobert Mustacchi 		if (strcmp(name, daddrstr) == 0) {
667*32002227SRobert Mustacchi 			return (dn);
668*32002227SRobert Mustacchi 		}
669*32002227SRobert Mustacchi 
670*32002227SRobert Mustacchi 		/*
671*32002227SRobert Mustacchi 		 * We didn't match on that, is there a driver?
672*32002227SRobert Mustacchi 		 */
673*32002227SRobert Mustacchi 		if (di_driver_name(dn) != NULL && di_instance(dn) != -1) {
674*32002227SRobert Mustacchi 			char buf[128];
675*32002227SRobert Mustacchi 
676*32002227SRobert Mustacchi 			(void) snprintf(buf, sizeof (buf), "%s%d",
677*32002227SRobert Mustacchi 			    di_driver_name(dn), di_instance(dn));
678*32002227SRobert Mustacchi 			if (strcmp(name, buf) == 0) {
679*32002227SRobert Mustacchi 				return (dn);
680*32002227SRobert Mustacchi 			}
681*32002227SRobert Mustacchi 		}
682*32002227SRobert Mustacchi 
683*32002227SRobert Mustacchi 		/*
684*32002227SRobert Mustacchi 		 * Finally check if we match name@addr. Only do this if we have
685*32002227SRobert Mustacchi 		 * an actual @ in the user bit.
686*32002227SRobert Mustacchi 		 */
687*32002227SRobert Mustacchi 		const char *at = strchr(name, '@');
688*32002227SRobert Mustacchi 		if (at != NULL) {
689*32002227SRobert Mustacchi 			char buf[128];
690*32002227SRobert Mustacchi 
691*32002227SRobert Mustacchi 			(void) snprintf(buf, sizeof (buf), "%s@%s",
692*32002227SRobert Mustacchi 			    di_node_name(dn), daddrstr);
693*32002227SRobert Mustacchi 			if (strcmp(name, buf) == 0) {
694*32002227SRobert Mustacchi 				return (dn);
695*32002227SRobert Mustacchi 			}
696*32002227SRobert Mustacchi 		}
697*32002227SRobert Mustacchi 	}
698*32002227SRobert Mustacchi 
699*32002227SRobert Mustacchi 	return (DI_NODE_NIL);
700*32002227SRobert Mustacchi }
701*32002227SRobert Mustacchi 
702*32002227SRobert Mustacchi bool
i2c_path_parse(i2c_hdl_t * hdl,const char * path,di_node_t root,di_node_t * dnp,i2c_node_type_t * typep,i2c_err_t err)703*32002227SRobert Mustacchi i2c_path_parse(i2c_hdl_t *hdl, const char *path, di_node_t root, di_node_t *dnp,
704*32002227SRobert Mustacchi     i2c_node_type_t *typep, i2c_err_t err)
705*32002227SRobert Mustacchi {
706*32002227SRobert Mustacchi 	di_node_t cur_devi;
707*32002227SRobert Mustacchi 	char *dup, *state;
708*32002227SRobert Mustacchi 	i2c_node_type_t cur;
709*32002227SRobert Mustacchi 	bool ret = false;
710*32002227SRobert Mustacchi 
711*32002227SRobert Mustacchi 	if (path == NULL) {
712*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
713*32002227SRobert Mustacchi 		    "invalid I2C path pointer: %p", path));
714*32002227SRobert Mustacchi 	}
715*32002227SRobert Mustacchi 
716*32002227SRobert Mustacchi 	dup = strdup(path);
717*32002227SRobert Mustacchi 	if (dup == NULL) {
718*32002227SRobert Mustacchi 		int e = errno;
719*32002227SRobert Mustacchi 		return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to duplicate "
720*32002227SRobert Mustacchi 		    "I2C path"));
721*32002227SRobert Mustacchi 	}
722*32002227SRobert Mustacchi 
723*32002227SRobert Mustacchi 	cur = I2C_NODE_T_OTHER;
724*32002227SRobert Mustacchi 	cur_devi = NULL;
725*32002227SRobert Mustacchi 	for (const char *ent = strtok_r(dup, "/", &state); ent != NULL;
726*32002227SRobert Mustacchi 	    ent = strtok_r(NULL, "/", &state)) {
727*32002227SRobert Mustacchi 		switch (cur) {
728*32002227SRobert Mustacchi 		case I2C_NODE_T_OTHER:
729*32002227SRobert Mustacchi 			/*
730*32002227SRobert Mustacchi 			 * This is our top-level state. We need to find a
731*32002227SRobert Mustacchi 			 * controller that matches this name.
732*32002227SRobert Mustacchi 			 */
733*32002227SRobert Mustacchi 			cur_devi = i2c_path_find_ctrl(root, ent);
734*32002227SRobert Mustacchi 			if (cur_devi == DI_NODE_NIL) {
735*32002227SRobert Mustacchi 				(void) i2c_error(hdl, err, 0,
736*32002227SRobert Mustacchi 				    "failed to find controller %s as part of "
737*32002227SRobert Mustacchi 				    "parsing I2C path %s", ent, path);
738*32002227SRobert Mustacchi 				goto err;
739*32002227SRobert Mustacchi 			}
740*32002227SRobert Mustacchi 			cur = I2C_NODE_T_CTRL;
741*32002227SRobert Mustacchi 			break;
742*32002227SRobert Mustacchi 		case I2C_NODE_T_DEV:
743*32002227SRobert Mustacchi 			/*
744*32002227SRobert Mustacchi 			 * Today we expect a device to only ever have a single
745*32002227SRobert Mustacchi 			 * node under it which is a mux. We walk all the
746*32002227SRobert Mustacchi 			 * children and look for this. This is because muxes
747*32002227SRobert Mustacchi 			 * aren't named. It's possible someone has created more
748*32002227SRobert Mustacchi 			 * than one node, so that's why we don't just go
749*32002227SRobert Mustacchi 			 * directly. After we do this, we explicitly fall
750*32002227SRobert Mustacchi 			 * through to the controller handling logic, as it has
751*32002227SRobert Mustacchi 			 * to do the same class.
752*32002227SRobert Mustacchi 			 */
753*32002227SRobert Mustacchi 			cur_devi = i2c_path_find_mux(cur_devi);
754*32002227SRobert Mustacchi 			if (cur_devi == DI_NODE_NIL) {
755*32002227SRobert Mustacchi 				(void) i2c_error(hdl, err, 0,
756*32002227SRobert Mustacchi 				    "failed to find mux %s as part of "
757*32002227SRobert Mustacchi 				    "parsing I2C path %s", ent, path);
758*32002227SRobert Mustacchi 				goto err;
759*32002227SRobert Mustacchi 			}
760*32002227SRobert Mustacchi 			/* FALLTHROUGH */
761*32002227SRobert Mustacchi 		case I2C_NODE_T_CTRL:
762*32002227SRobert Mustacchi 			cur_devi = i2c_path_find_port(cur_devi, ent);
763*32002227SRobert Mustacchi 			if (cur_devi == DI_NODE_NIL) {
764*32002227SRobert Mustacchi 				(void) i2c_error(hdl, err, 0,
765*32002227SRobert Mustacchi 				    "failed to find port %s as part of "
766*32002227SRobert Mustacchi 				    "parsing I2C path %s", ent, path);
767*32002227SRobert Mustacchi 				goto err;
768*32002227SRobert Mustacchi 			}
769*32002227SRobert Mustacchi 			cur = I2C_NODE_T_PORT;
770*32002227SRobert Mustacchi 			break;
771*32002227SRobert Mustacchi 		case I2C_NODE_T_PORT:
772*32002227SRobert Mustacchi 			cur_devi = i2c_path_find_device(hdl, cur_devi, ent);
773*32002227SRobert Mustacchi 			if (cur_devi == DI_NODE_NIL) {
774*32002227SRobert Mustacchi 				(void) i2c_error(hdl, err, 0,
775*32002227SRobert Mustacchi 				    "failed to find device %s as part of "
776*32002227SRobert Mustacchi 				    "parsing I2C path %s", ent, path);
777*32002227SRobert Mustacchi 				goto err;
778*32002227SRobert Mustacchi 			}
779*32002227SRobert Mustacchi 			cur = I2C_NODE_T_DEV;
780*32002227SRobert Mustacchi 			break;
781*32002227SRobert Mustacchi 		default:
782*32002227SRobert Mustacchi 			abort();
783*32002227SRobert Mustacchi 		}
784*32002227SRobert Mustacchi 	}
785*32002227SRobert Mustacchi 
786*32002227SRobert Mustacchi 	*dnp = cur_devi;
787*32002227SRobert Mustacchi 	*typep = cur;
788*32002227SRobert Mustacchi 	ret = true;
789*32002227SRobert Mustacchi 
790*32002227SRobert Mustacchi err:
791*32002227SRobert Mustacchi 	free(dup);
792*32002227SRobert Mustacchi 	return (ret);
793*32002227SRobert Mustacchi }
794