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", ®);
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", ®);
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