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 * I2C port discovery and initialization.
18*32002227SRobert Mustacchi */
19*32002227SRobert Mustacchi
20*32002227SRobert Mustacchi #include <stdlib.h>
21*32002227SRobert Mustacchi #include <string.h>
22*32002227SRobert Mustacchi #include <unistd.h>
23*32002227SRobert Mustacchi #include <sys/types.h>
24*32002227SRobert Mustacchi #include <sys/stat.h>
25*32002227SRobert Mustacchi #include <fcntl.h>
26*32002227SRobert Mustacchi
27*32002227SRobert Mustacchi #include "libi2c_impl.h"
28*32002227SRobert Mustacchi
29*32002227SRobert Mustacchi void
i2c_port_discover_fini(i2c_port_iter_t * iter)30*32002227SRobert Mustacchi i2c_port_discover_fini(i2c_port_iter_t *iter)
31*32002227SRobert Mustacchi {
32*32002227SRobert Mustacchi if (iter == NULL) {
33*32002227SRobert Mustacchi return;
34*32002227SRobert Mustacchi }
35*32002227SRobert Mustacchi
36*32002227SRobert Mustacchi free(iter->pi_ports);
37*32002227SRobert Mustacchi di_fini(iter->pi_root);
38*32002227SRobert Mustacchi free(iter);
39*32002227SRobert Mustacchi }
40*32002227SRobert Mustacchi
41*32002227SRobert Mustacchi i2c_iter_t
i2c_port_discover_step(i2c_port_iter_t * iter,const i2c_port_disc_t ** discp)42*32002227SRobert Mustacchi i2c_port_discover_step(i2c_port_iter_t *iter, const i2c_port_disc_t **discp)
43*32002227SRobert Mustacchi {
44*32002227SRobert Mustacchi for (;;) {
45*32002227SRobert Mustacchi if (iter->pi_curport == iter->pi_nports) {
46*32002227SRobert Mustacchi return (I2C_ITER_DONE);
47*32002227SRobert Mustacchi }
48*32002227SRobert Mustacchi
49*32002227SRobert Mustacchi iter->pi_disc.pd_devi = iter->pi_ports[iter->pi_curport];
50*32002227SRobert Mustacchi iter->pi_curport++;
51*32002227SRobert Mustacchi
52*32002227SRobert Mustacchi if (!i2c_node_to_path(iter->pi_hdl, iter->pi_disc.pd_devi,
53*32002227SRobert Mustacchi iter->pi_disc.pd_path, sizeof (iter->pi_disc.pd_path))) {
54*32002227SRobert Mustacchi continue;
55*32002227SRobert Mustacchi }
56*32002227SRobert Mustacchi
57*32002227SRobert Mustacchi *discp = &iter->pi_disc;
58*32002227SRobert Mustacchi return (I2C_ITER_VALID);
59*32002227SRobert Mustacchi }
60*32002227SRobert Mustacchi }
61*32002227SRobert Mustacchi
62*32002227SRobert Mustacchi /*
63*32002227SRobert Mustacchi * We have two nodes that are not the same. They are at the same point in the
64*32002227SRobert Mustacchi * tree though. We expect all devices at a given layer in the tree to have the
65*32002227SRobert Mustacchi * same type. We start with the node name and if they're the same fall back to
66*32002227SRobert Mustacchi * the bus address which must be unique at this point.
67*32002227SRobert Mustacchi */
68*32002227SRobert Mustacchi static int
i2c_port_sort_node(di_node_t l,di_node_t r)69*32002227SRobert Mustacchi i2c_port_sort_node(di_node_t l, di_node_t r)
70*32002227SRobert Mustacchi {
71*32002227SRobert Mustacchi const char *nl = di_node_name(l);
72*32002227SRobert Mustacchi const char *nr = di_node_name(r);
73*32002227SRobert Mustacchi int ret;
74*32002227SRobert Mustacchi
75*32002227SRobert Mustacchi if ((ret = strcmp(nl, nr)) == 0) {
76*32002227SRobert Mustacchi nl = di_bus_addr(l);
77*32002227SRobert Mustacchi nr = di_bus_addr(r);
78*32002227SRobert Mustacchi ret = strcmp(nl, nr);
79*32002227SRobert Mustacchi }
80*32002227SRobert Mustacchi
81*32002227SRobert Mustacchi return (ret);
82*32002227SRobert Mustacchi }
83*32002227SRobert Mustacchi
84*32002227SRobert Mustacchi typedef struct {
85*32002227SRobert Mustacchi di_node_t ni_ctrl;
86*32002227SRobert Mustacchi di_node_t ni_parent;
87*32002227SRobert Mustacchi uint32_t ni_height;
88*32002227SRobert Mustacchi } node_info_t;
89*32002227SRobert Mustacchi
90*32002227SRobert Mustacchi static void
i2c_port_sort_info(di_node_t dn,node_info_t * info)91*32002227SRobert Mustacchi i2c_port_sort_info(di_node_t dn, node_info_t *info)
92*32002227SRobert Mustacchi {
93*32002227SRobert Mustacchi (void) memset(info, 0, sizeof (node_info_t));
94*32002227SRobert Mustacchi
95*32002227SRobert Mustacchi info->ni_parent = di_parent_node(dn);
96*32002227SRobert Mustacchi for (;;) {
97*32002227SRobert Mustacchi i2c_node_type_t type = i2c_node_type(dn);
98*32002227SRobert Mustacchi
99*32002227SRobert Mustacchi if (type == I2C_NODE_T_CTRL) {
100*32002227SRobert Mustacchi info->ni_ctrl = dn;
101*32002227SRobert Mustacchi return;
102*32002227SRobert Mustacchi }
103*32002227SRobert Mustacchi
104*32002227SRobert Mustacchi info->ni_height++;
105*32002227SRobert Mustacchi dn = di_parent_node(dn);
106*32002227SRobert Mustacchi if (dn == DI_NODE_NIL) {
107*32002227SRobert Mustacchi return;
108*32002227SRobert Mustacchi }
109*32002227SRobert Mustacchi }
110*32002227SRobert Mustacchi }
111*32002227SRobert Mustacchi
112*32002227SRobert Mustacchi static int
i2c_port_sort(const void * left,const void * right)113*32002227SRobert Mustacchi i2c_port_sort(const void *left, const void *right)
114*32002227SRobert Mustacchi {
115*32002227SRobert Mustacchi di_node_t l = *(di_node_t *)left;
116*32002227SRobert Mustacchi di_node_t r = *(di_node_t *)right;
117*32002227SRobert Mustacchi node_info_t li, ri;
118*32002227SRobert Mustacchi
119*32002227SRobert Mustacchi if (l == r) {
120*32002227SRobert Mustacchi return (0);
121*32002227SRobert Mustacchi }
122*32002227SRobert Mustacchi
123*32002227SRobert Mustacchi /*
124*32002227SRobert Mustacchi * We have two nodes that are different points in the tree. We basically
125*32002227SRobert Mustacchi * want to ask:
126*32002227SRobert Mustacchi *
127*32002227SRobert Mustacchi * - What controller do they point to?
128*32002227SRobert Mustacchi * - What are the relative heights in the tree?
129*32002227SRobert Mustacchi *
130*32002227SRobert Mustacchi * If they belong to different controllers, we sort based on the
131*32002227SRobert Mustacchi * controller's name. If they belong to the same controller, then we use
132*32002227SRobert Mustacchi * the height in the tree. If they have the same height, we then see if
133*32002227SRobert Mustacchi * they have the same parent. If they don't, we sort on the parent (like
134*32002227SRobert Mustacchi * the controller). If they do, we use their name directly.
135*32002227SRobert Mustacchi */
136*32002227SRobert Mustacchi i2c_port_sort_info(l, &li);
137*32002227SRobert Mustacchi i2c_port_sort_info(r, &ri);
138*32002227SRobert Mustacchi
139*32002227SRobert Mustacchi if (li.ni_ctrl != ri.ni_ctrl) {
140*32002227SRobert Mustacchi return (i2c_port_sort_node(li.ni_ctrl, ri.ni_ctrl));
141*32002227SRobert Mustacchi }
142*32002227SRobert Mustacchi
143*32002227SRobert Mustacchi if (li.ni_height != ri.ni_height) {
144*32002227SRobert Mustacchi return (li.ni_height < ri.ni_height ? -1 : 1);
145*32002227SRobert Mustacchi }
146*32002227SRobert Mustacchi
147*32002227SRobert Mustacchi if (li.ni_parent != ri.ni_parent) {
148*32002227SRobert Mustacchi return (i2c_port_sort_node(li.ni_parent, ri.ni_parent));
149*32002227SRobert Mustacchi }
150*32002227SRobert Mustacchi
151*32002227SRobert Mustacchi return (i2c_port_sort_node(l, r));
152*32002227SRobert Mustacchi }
153*32002227SRobert Mustacchi bool
i2c_port_discover_init(i2c_hdl_t * hdl,i2c_port_iter_t ** iterp)154*32002227SRobert Mustacchi i2c_port_discover_init(i2c_hdl_t *hdl, i2c_port_iter_t **iterp)
155*32002227SRobert Mustacchi {
156*32002227SRobert Mustacchi i2c_port_iter_t *iter;
157*32002227SRobert Mustacchi
158*32002227SRobert Mustacchi if (iterp == NULL) {
159*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
160*32002227SRobert Mustacchi "invalid i2c_port_iter_t output pointer: %p", iterp));
161*32002227SRobert Mustacchi }
162*32002227SRobert Mustacchi
163*32002227SRobert Mustacchi iter = calloc(1, sizeof (i2c_port_iter_t));
164*32002227SRobert Mustacchi if (iter == NULL) {
165*32002227SRobert Mustacchi int e = errno;
166*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
167*32002227SRobert Mustacchi "memory for a new i2c_port_iter_t"));
168*32002227SRobert Mustacchi }
169*32002227SRobert Mustacchi
170*32002227SRobert Mustacchi iter->pi_root = di_init("/", DINFOCPYALL);
171*32002227SRobert Mustacchi if (iter->pi_root == NULL) {
172*32002227SRobert Mustacchi int e = errno;
173*32002227SRobert Mustacchi i2c_port_discover_fini(iter);
174*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
175*32002227SRobert Mustacchi "initialize devinfo snapshot: %s", strerrordesc_np(e)));
176*32002227SRobert Mustacchi }
177*32002227SRobert Mustacchi iter->pi_done = false;
178*32002227SRobert Mustacchi
179*32002227SRobert Mustacchi /*
180*32002227SRobert Mustacchi * We want port discovery to have a reasonably stable and meaningful
181*32002227SRobert Mustacchi * order. This is going to be built on top of for devices. We want to
182*32002227SRobert Mustacchi * treat this in a bit of a depth-search sense. We don't want to do the
183*32002227SRobert Mustacchi * children of one controller's port, then switch to a different
184*32002227SRobert Mustacchi * controller, and then come back to say a mux. To facilitate this, note
185*32002227SRobert Mustacchi * all the ports first, sort them, and then come back to it.
186*32002227SRobert Mustacchi */
187*32002227SRobert Mustacchi for (di_node_t dn = di_drv_first_node(I2C_NEX_DRV, iter->pi_root);
188*32002227SRobert Mustacchi dn != NULL; dn = di_drv_next_node(dn)) {
189*32002227SRobert Mustacchi if (!i2c_node_is_type(dn, I2C_NODE_T_PORT)) {
190*32002227SRobert Mustacchi continue;
191*32002227SRobert Mustacchi }
192*32002227SRobert Mustacchi
193*32002227SRobert Mustacchi if (iter->pi_nalloc == iter->pi_nports) {
194*32002227SRobert Mustacchi di_node_t *new;
195*32002227SRobert Mustacchi uint32_t toalloc = iter->pi_nalloc + 16;
196*32002227SRobert Mustacchi
197*32002227SRobert Mustacchi new = recallocarray(iter->pi_ports, iter->pi_nports,
198*32002227SRobert Mustacchi toalloc, sizeof (di_node_t));
199*32002227SRobert Mustacchi if (new == NULL) {
200*32002227SRobert Mustacchi int e = errno;
201*32002227SRobert Mustacchi i2c_port_discover_fini(iter);
202*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e,
203*32002227SRobert Mustacchi "failed to allocate memory for a %u "
204*32002227SRobert Mustacchi "element di_node_t array",
205*32002227SRobert Mustacchi toalloc));
206*32002227SRobert Mustacchi }
207*32002227SRobert Mustacchi iter->pi_ports = new;
208*32002227SRobert Mustacchi iter->pi_nalloc = toalloc;
209*32002227SRobert Mustacchi }
210*32002227SRobert Mustacchi
211*32002227SRobert Mustacchi iter->pi_ports[iter->pi_nports] = dn;
212*32002227SRobert Mustacchi iter->pi_nports++;
213*32002227SRobert Mustacchi }
214*32002227SRobert Mustacchi
215*32002227SRobert Mustacchi qsort(iter->pi_ports, iter->pi_nports, sizeof (di_node_t),
216*32002227SRobert Mustacchi i2c_port_sort);
217*32002227SRobert Mustacchi
218*32002227SRobert Mustacchi *iterp = iter;
219*32002227SRobert Mustacchi return (i2c_success(hdl));
220*32002227SRobert Mustacchi }
221*32002227SRobert Mustacchi
222*32002227SRobert Mustacchi bool
i2c_port_discover(i2c_hdl_t * hdl,i2c_port_disc_f func,void * arg)223*32002227SRobert Mustacchi i2c_port_discover(i2c_hdl_t *hdl, i2c_port_disc_f func, void *arg)
224*32002227SRobert Mustacchi {
225*32002227SRobert Mustacchi i2c_port_iter_t *iter;
226*32002227SRobert Mustacchi const i2c_port_disc_t *disc;
227*32002227SRobert Mustacchi i2c_iter_t ret;
228*32002227SRobert Mustacchi
229*32002227SRobert Mustacchi if (func == NULL) {
230*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
231*32002227SRobert Mustacchi "invalid i2c_port_disc_f function pointer: %p", func));
232*32002227SRobert Mustacchi }
233*32002227SRobert Mustacchi
234*32002227SRobert Mustacchi if (!i2c_port_discover_init(hdl, &iter)) {
235*32002227SRobert Mustacchi return (false);
236*32002227SRobert Mustacchi }
237*32002227SRobert Mustacchi
238*32002227SRobert Mustacchi while ((ret = i2c_port_discover_step(iter, &disc)) == I2C_ITER_VALID) {
239*32002227SRobert Mustacchi if (!func(hdl, disc, arg))
240*32002227SRobert Mustacchi break;
241*32002227SRobert Mustacchi }
242*32002227SRobert Mustacchi
243*32002227SRobert Mustacchi i2c_port_discover_fini(iter);
244*32002227SRobert Mustacchi if (ret == I2C_ITER_ERROR) {
245*32002227SRobert Mustacchi return (false);
246*32002227SRobert Mustacchi }
247*32002227SRobert Mustacchi
248*32002227SRobert Mustacchi return (i2c_success(hdl));
249*32002227SRobert Mustacchi }
250*32002227SRobert Mustacchi
251*32002227SRobert Mustacchi di_node_t
i2c_port_disc_devi(const i2c_port_disc_t * disc)252*32002227SRobert Mustacchi i2c_port_disc_devi(const i2c_port_disc_t *disc)
253*32002227SRobert Mustacchi {
254*32002227SRobert Mustacchi return (disc->pd_devi);
255*32002227SRobert Mustacchi }
256*32002227SRobert Mustacchi
257*32002227SRobert Mustacchi const char *
i2c_port_disc_path(const i2c_port_disc_t * disc)258*32002227SRobert Mustacchi i2c_port_disc_path(const i2c_port_disc_t *disc)
259*32002227SRobert Mustacchi {
260*32002227SRobert Mustacchi return (disc->pd_path);
261*32002227SRobert Mustacchi }
262*32002227SRobert Mustacchi
263*32002227SRobert Mustacchi void
i2c_port_fini(i2c_port_t * port)264*32002227SRobert Mustacchi i2c_port_fini(i2c_port_t *port)
265*32002227SRobert Mustacchi {
266*32002227SRobert Mustacchi if (port == NULL) {
267*32002227SRobert Mustacchi return;
268*32002227SRobert Mustacchi }
269*32002227SRobert Mustacchi
270*32002227SRobert Mustacchi if (port->port_fd >= 0) {
271*32002227SRobert Mustacchi (void) close(port->port_fd);
272*32002227SRobert Mustacchi }
273*32002227SRobert Mustacchi
274*32002227SRobert Mustacchi di_devfs_path_free(port->port_minor);
275*32002227SRobert Mustacchi free(port->port_name);
276*32002227SRobert Mustacchi free(port);
277*32002227SRobert Mustacchi }
278*32002227SRobert Mustacchi
279*32002227SRobert Mustacchi bool
i2c_port_init(i2c_hdl_t * hdl,di_node_t di,i2c_port_t ** portp)280*32002227SRobert Mustacchi i2c_port_init(i2c_hdl_t *hdl, di_node_t di, i2c_port_t **portp)
281*32002227SRobert Mustacchi {
282*32002227SRobert Mustacchi di_minor_t minor;
283*32002227SRobert Mustacchi di_node_t parent;
284*32002227SRobert Mustacchi i2c_node_type_t ptype;
285*32002227SRobert Mustacchi
286*32002227SRobert Mustacchi if (di == NULL) {
287*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
288*32002227SRobert Mustacchi "invalid di_node_t: %p", di));
289*32002227SRobert Mustacchi }
290*32002227SRobert Mustacchi
291*32002227SRobert Mustacchi if (portp == NULL) {
292*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
293*32002227SRobert Mustacchi "invalid i2c_port_t output pointer: %p", portp));
294*32002227SRobert Mustacchi }
295*32002227SRobert Mustacchi
296*32002227SRobert Mustacchi /*
297*32002227SRobert Mustacchi * We've verified that we were given an i2cnex instance, make sure this
298*32002227SRobert Mustacchi * corresponds to a port.
299*32002227SRobert Mustacchi */
300*32002227SRobert Mustacchi if (!i2c_node_is_type(di, I2C_NODE_T_PORT)) {
301*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVI, 0, "devi %s@%s is "
302*32002227SRobert Mustacchi "not an i2c port", di_node_name(di), di_bus_addr(di)));
303*32002227SRobert Mustacchi }
304*32002227SRobert Mustacchi
305*32002227SRobert Mustacchi minor = i2c_node_minor(di);
306*32002227SRobert Mustacchi if (minor == DI_MINOR_NIL) {
307*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVI, 0, "devi %s@%s is "
308*32002227SRobert Mustacchi "not an i2c port: failed to find port minor",
309*32002227SRobert Mustacchi di_node_name(di), di_bus_addr(di)));
310*32002227SRobert Mustacchi }
311*32002227SRobert Mustacchi
312*32002227SRobert Mustacchi i2c_port_t *port = calloc(1, sizeof (i2c_port_t));
313*32002227SRobert Mustacchi if (port == NULL) {
314*32002227SRobert Mustacchi int e = errno;
315*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
316*32002227SRobert Mustacchi "memory for a new i2c_port_t"));
317*32002227SRobert Mustacchi }
318*32002227SRobert Mustacchi
319*32002227SRobert Mustacchi port->port_fd = -1;
320*32002227SRobert Mustacchi port->port_hdl = hdl;
321*32002227SRobert Mustacchi port->port_inst = di_instance(di);
322*32002227SRobert Mustacchi port->port_name = strdup(di_bus_addr(di));
323*32002227SRobert Mustacchi if (port->port_name == NULL) {
324*32002227SRobert Mustacchi int e = errno;
325*32002227SRobert Mustacchi i2c_port_fini(port);
326*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to duplicate "
327*32002227SRobert Mustacchi "port bus address"));
328*32002227SRobert Mustacchi }
329*32002227SRobert Mustacchi
330*32002227SRobert Mustacchi parent = di_parent_node(di);
331*32002227SRobert Mustacchi ptype = i2c_node_type(parent);
332*32002227SRobert Mustacchi if (ptype == I2C_NODE_T_CTRL) {
333*32002227SRobert Mustacchi port->port_type = I2C_PORT_TYPE_CTRL;
334*32002227SRobert Mustacchi } else if (ptype == I2C_NODE_T_MUX) {
335*32002227SRobert Mustacchi port->port_type = I2C_PORT_TYPE_MUX;
336*32002227SRobert Mustacchi } else {
337*32002227SRobert Mustacchi i2c_port_fini(port);
338*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVI, 0, "devi %s@%s is not "
339*32002227SRobert Mustacchi "an i2c port: found wrong parent", di_node_name(di),
340*32002227SRobert Mustacchi di_bus_addr(di)));
341*32002227SRobert Mustacchi }
342*32002227SRobert Mustacchi
343*32002227SRobert Mustacchi if (!i2c_node_to_path(hdl, di, port->port_path,
344*32002227SRobert Mustacchi sizeof (port->port_path))) {
345*32002227SRobert Mustacchi i2c_port_fini(port);
346*32002227SRobert Mustacchi return (false);
347*32002227SRobert Mustacchi }
348*32002227SRobert Mustacchi
349*32002227SRobert Mustacchi port->port_minor = di_devfs_minor_path(minor);
350*32002227SRobert Mustacchi if (port->port_minor == NULL) {
351*32002227SRobert Mustacchi int e = errno;
352*32002227SRobert Mustacchi i2c_port_fini(port);
353*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
354*32002227SRobert Mustacchi "obtain ports's devfs path: %s", strerrordesc_np(e)));
355*32002227SRobert Mustacchi }
356*32002227SRobert Mustacchi
357*32002227SRobert Mustacchi port->port_fd = openat(hdl->ih_devfd, port->port_minor + 1, O_RDWR);
358*32002227SRobert Mustacchi if (port->port_fd < 0) {
359*32002227SRobert Mustacchi int e = errno;
360*32002227SRobert Mustacchi (void) i2c_error(hdl, I2C_ERR_OPEN_DEV, e, "failed to open "
361*32002227SRobert Mustacchi "device path /devices%s: %s", port->port_minor,
362*32002227SRobert Mustacchi strerrordesc_np(e));
363*32002227SRobert Mustacchi i2c_port_fini(port);
364*32002227SRobert Mustacchi return (false);
365*32002227SRobert Mustacchi }
366*32002227SRobert Mustacchi
367*32002227SRobert Mustacchi if (ioctl(port->port_fd, UI2C_IOCTL_PORT_INFO, &port->port_info) != 0) {
368*32002227SRobert Mustacchi int e = errno;
369*32002227SRobert Mustacchi i2c_port_fini(port);
370*32002227SRobert Mustacchi return (i2c_ioctl_syserror(hdl, e, "port information request"));
371*32002227SRobert Mustacchi }
372*32002227SRobert Mustacchi
373*32002227SRobert Mustacchi if (port->port_info.upo_error.i2c_error != I2C_CORE_E_OK) {
374*32002227SRobert Mustacchi return (i2c_ioctl_error(hdl, &port->port_info.upo_error,
375*32002227SRobert Mustacchi "port information request"));
376*32002227SRobert Mustacchi }
377*32002227SRobert Mustacchi
378*32002227SRobert Mustacchi *portp = port;
379*32002227SRobert Mustacchi return (i2c_success(hdl));
380*32002227SRobert Mustacchi }
381*32002227SRobert Mustacchi
382*32002227SRobert Mustacchi /*
383*32002227SRobert Mustacchi * Initialize a port based on the passed in name. This name may be a top-level
384*32002227SRobert Mustacchi * port for the controller or it may be a port on a mux. We end up walking the
385*32002227SRobert Mustacchi * path, tokenizing and parsing it to try to find something here.
386*32002227SRobert Mustacchi */
387*32002227SRobert Mustacchi bool
i2c_port_init_by_path(i2c_hdl_t * hdl,const char * path,i2c_port_t ** portp)388*32002227SRobert Mustacchi i2c_port_init_by_path(i2c_hdl_t *hdl, const char *path, i2c_port_t **portp)
389*32002227SRobert Mustacchi {
390*32002227SRobert Mustacchi i2c_node_type_t type;
391*32002227SRobert Mustacchi di_node_t dn, root;
392*32002227SRobert Mustacchi
393*32002227SRobert Mustacchi if (path == NULL) {
394*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
395*32002227SRobert Mustacchi "invalid i2c port path: %p", path));
396*32002227SRobert Mustacchi }
397*32002227SRobert Mustacchi
398*32002227SRobert Mustacchi if (portp == NULL) {
399*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
400*32002227SRobert Mustacchi "invalid i2c_port_t output pointer: %p", portp));
401*32002227SRobert Mustacchi }
402*32002227SRobert Mustacchi
403*32002227SRobert Mustacchi root = di_init("/", DINFOCPYALL);
404*32002227SRobert Mustacchi if (root == DI_NODE_NIL) {
405*32002227SRobert Mustacchi int e = errno;
406*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
407*32002227SRobert Mustacchi "initialize devinfo snapshot: %s", strerrordesc_np(e)));
408*32002227SRobert Mustacchi }
409*32002227SRobert Mustacchi
410*32002227SRobert Mustacchi if (!i2c_path_parse(hdl, path, root, &dn, &type, I2C_ERR_BAD_PORT)) {
411*32002227SRobert Mustacchi di_fini(root);
412*32002227SRobert Mustacchi return (false);
413*32002227SRobert Mustacchi }
414*32002227SRobert Mustacchi
415*32002227SRobert Mustacchi if (type != I2C_NODE_T_PORT) {
416*32002227SRobert Mustacchi di_fini(root);
417*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PORT, 0, "parsed I2C path "
418*32002227SRobert Mustacchi "%s did not end at a port", path));
419*32002227SRobert Mustacchi }
420*32002227SRobert Mustacchi
421*32002227SRobert Mustacchi bool ret = i2c_port_init(hdl, dn, portp);
422*32002227SRobert Mustacchi di_fini(root);
423*32002227SRobert Mustacchi return (ret);
424*32002227SRobert Mustacchi }
425*32002227SRobert Mustacchi
426*32002227SRobert Mustacchi const char *
i2c_port_name(i2c_port_t * port)427*32002227SRobert Mustacchi i2c_port_name(i2c_port_t *port)
428*32002227SRobert Mustacchi {
429*32002227SRobert Mustacchi return (port->port_name);
430*32002227SRobert Mustacchi }
431*32002227SRobert Mustacchi
432*32002227SRobert Mustacchi const char *
i2c_port_path(i2c_port_t * port)433*32002227SRobert Mustacchi i2c_port_path(i2c_port_t *port)
434*32002227SRobert Mustacchi {
435*32002227SRobert Mustacchi return (port->port_path);
436*32002227SRobert Mustacchi }
437*32002227SRobert Mustacchi
438*32002227SRobert Mustacchi uint32_t
i2c_port_portno(i2c_port_t * port)439*32002227SRobert Mustacchi i2c_port_portno(i2c_port_t *port)
440*32002227SRobert Mustacchi {
441*32002227SRobert Mustacchi return (port->port_info.upo_portno);
442*32002227SRobert Mustacchi }
443*32002227SRobert Mustacchi
444*32002227SRobert Mustacchi i2c_port_type_t
i2c_port_type(i2c_port_t * port)445*32002227SRobert Mustacchi i2c_port_type(i2c_port_t *port)
446*32002227SRobert Mustacchi {
447*32002227SRobert Mustacchi return (port->port_type);
448*32002227SRobert Mustacchi }
449*32002227SRobert Mustacchi
450*32002227SRobert Mustacchi void
i2c_port_map_free(i2c_port_map_t * map)451*32002227SRobert Mustacchi i2c_port_map_free(i2c_port_map_t *map)
452*32002227SRobert Mustacchi {
453*32002227SRobert Mustacchi free(map);
454*32002227SRobert Mustacchi }
455*32002227SRobert Mustacchi
456*32002227SRobert Mustacchi bool
i2c_port_map_snap(i2c_port_t * port,i2c_port_map_t ** mapp)457*32002227SRobert Mustacchi i2c_port_map_snap(i2c_port_t *port, i2c_port_map_t **mapp)
458*32002227SRobert Mustacchi {
459*32002227SRobert Mustacchi i2c_port_map_t *map;
460*32002227SRobert Mustacchi i2c_hdl_t *hdl = port->port_hdl;
461*32002227SRobert Mustacchi
462*32002227SRobert Mustacchi if (mapp == NULL) {
463*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
464*32002227SRobert Mustacchi "invalid i2c_port_map_t output pointer: %p", mapp));
465*32002227SRobert Mustacchi }
466*32002227SRobert Mustacchi
467*32002227SRobert Mustacchi map = calloc(1, sizeof (i2c_port_map_t));
468*32002227SRobert Mustacchi if (map == NULL) {
469*32002227SRobert Mustacchi int e = errno;
470*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
471*32002227SRobert Mustacchi "memory for a new i2c_port_map_t"));
472*32002227SRobert Mustacchi }
473*32002227SRobert Mustacchi map->pm_hdl = hdl;
474*32002227SRobert Mustacchi
475*32002227SRobert Mustacchi if (ioctl(port->port_fd, UI2C_IOCTL_PORT_INFO, &map->pm_info) != 0) {
476*32002227SRobert Mustacchi int e = errno;
477*32002227SRobert Mustacchi i2c_port_fini(port);
478*32002227SRobert Mustacchi return (i2c_ioctl_syserror(hdl, e, "port maprmation request"));
479*32002227SRobert Mustacchi }
480*32002227SRobert Mustacchi
481*32002227SRobert Mustacchi if (map->pm_info.upo_error.i2c_error != I2C_CORE_E_OK) {
482*32002227SRobert Mustacchi return (i2c_ioctl_error(hdl, &map->pm_info.upo_error,
483*32002227SRobert Mustacchi "port information request"));
484*32002227SRobert Mustacchi }
485*32002227SRobert Mustacchi
486*32002227SRobert Mustacchi *mapp = map;
487*32002227SRobert Mustacchi return (i2c_success(hdl));
488*32002227SRobert Mustacchi }
489*32002227SRobert Mustacchi
490*32002227SRobert Mustacchi void
i2c_port_map_ndevs(const i2c_port_map_t * map,uint32_t * local,uint32_t * ds)491*32002227SRobert Mustacchi i2c_port_map_ndevs(const i2c_port_map_t *map, uint32_t *local, uint32_t *ds)
492*32002227SRobert Mustacchi {
493*32002227SRobert Mustacchi if (local != NULL) {
494*32002227SRobert Mustacchi *local = map->pm_info.upo_ndevs;
495*32002227SRobert Mustacchi }
496*32002227SRobert Mustacchi
497*32002227SRobert Mustacchi if (ds != NULL) {
498*32002227SRobert Mustacchi *ds = map->pm_info.upo_ndevs_ds;
499*32002227SRobert Mustacchi }
500*32002227SRobert Mustacchi }
501*32002227SRobert Mustacchi
502*32002227SRobert Mustacchi bool
i2c_port_map_addr_info(const i2c_port_map_t * map,const i2c_addr_t * addr,uint32_t * devsp,bool * dsp,major_t * majorp)503*32002227SRobert Mustacchi i2c_port_map_addr_info(const i2c_port_map_t *map, const i2c_addr_t *addr,
504*32002227SRobert Mustacchi uint32_t *devsp, bool *dsp, major_t *majorp)
505*32002227SRobert Mustacchi {
506*32002227SRobert Mustacchi if (!i2c_addr_validate(map->pm_hdl, addr)) {
507*32002227SRobert Mustacchi return (false);
508*32002227SRobert Mustacchi }
509*32002227SRobert Mustacchi
510*32002227SRobert Mustacchi if (addr->ia_type != I2C_ADDR_7BIT) {
511*32002227SRobert Mustacchi (void) i2c_error(map->pm_hdl, I2C_ERR_UNSUP_ADDR_TYPE, 0,
512*32002227SRobert Mustacchi "port map information is not available for this address "
513*32002227SRobert Mustacchi "type");
514*32002227SRobert Mustacchi return (false);
515*32002227SRobert Mustacchi }
516*32002227SRobert Mustacchi
517*32002227SRobert Mustacchi const ui2c_port_addr_info_t *info = &map->pm_info.upo_7b[addr->ia_addr];
518*32002227SRobert Mustacchi
519*32002227SRobert Mustacchi if (devsp != NULL) {
520*32002227SRobert Mustacchi *devsp = info->pai_ndevs;
521*32002227SRobert Mustacchi }
522*32002227SRobert Mustacchi
523*32002227SRobert Mustacchi if (dsp != NULL) {
524*32002227SRobert Mustacchi *dsp = info->pai_downstream;
525*32002227SRobert Mustacchi }
526*32002227SRobert Mustacchi
527*32002227SRobert Mustacchi if (majorp != NULL) {
528*32002227SRobert Mustacchi *majorp = info->pai_major;
529*32002227SRobert Mustacchi }
530*32002227SRobert Mustacchi
531*32002227SRobert Mustacchi
532*32002227SRobert Mustacchi return (i2c_success(map->pm_hdl));
533*32002227SRobert Mustacchi }
534