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 * Device addition, removal, and discovery
18*32002227SRobert Mustacchi */
19*32002227SRobert Mustacchi
20*32002227SRobert Mustacchi #include <stdlib.h>
21*32002227SRobert Mustacchi #include <strings.h>
22*32002227SRobert Mustacchi #include <unistd.h>
23*32002227SRobert Mustacchi #include <sys/sysmacros.h>
24*32002227SRobert Mustacchi #include <sys/debug.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_device_add_req_fini(i2c_dev_add_req_t * req)30*32002227SRobert Mustacchi i2c_device_add_req_fini(i2c_dev_add_req_t *req)
31*32002227SRobert Mustacchi {
32*32002227SRobert Mustacchi nvlist_free(req->add_nvl);
33*32002227SRobert Mustacchi free(req);
34*32002227SRobert Mustacchi }
35*32002227SRobert Mustacchi
36*32002227SRobert Mustacchi bool
i2c_device_add_req_init(i2c_port_t * port,i2c_dev_add_req_t ** reqp)37*32002227SRobert Mustacchi i2c_device_add_req_init(i2c_port_t *port, i2c_dev_add_req_t **reqp)
38*32002227SRobert Mustacchi {
39*32002227SRobert Mustacchi i2c_hdl_t *hdl = port->port_hdl;
40*32002227SRobert Mustacchi i2c_dev_add_req_t *req;
41*32002227SRobert Mustacchi
42*32002227SRobert Mustacchi if (reqp == NULL) {
43*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
44*32002227SRobert Mustacchi "invalid i2c_dev_add_req_t output pointer: %p", reqp));
45*32002227SRobert Mustacchi }
46*32002227SRobert Mustacchi
47*32002227SRobert Mustacchi req = calloc(1, sizeof (i2c_dev_add_req_t));
48*32002227SRobert Mustacchi if (req == NULL) {
49*32002227SRobert Mustacchi int e = errno;
50*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
51*32002227SRobert Mustacchi "memory for a new i2c_dev_add_req_t"));
52*32002227SRobert Mustacchi }
53*32002227SRobert Mustacchi req->add_port = port;
54*32002227SRobert Mustacchi req->add_need = I2C_DEV_ADD_REQ_FIELD_NAME | I2C_DEV_ADD_REQ_FIELD_ADDR;
55*32002227SRobert Mustacchi
56*32002227SRobert Mustacchi int ret = nvlist_alloc(&req->add_nvl, NV_UNIQUE_NAME, 0);
57*32002227SRobert Mustacchi if (!i2c_nvlist_error(hdl, ret, "create a nvlist")) {
58*32002227SRobert Mustacchi free(req);
59*32002227SRobert Mustacchi return (false);
60*32002227SRobert Mustacchi }
61*32002227SRobert Mustacchi
62*32002227SRobert Mustacchi *reqp = req;
63*32002227SRobert Mustacchi return (i2c_success(hdl));
64*32002227SRobert Mustacchi }
65*32002227SRobert Mustacchi
66*32002227SRobert Mustacchi bool
i2c_device_add_req_set_addr(i2c_dev_add_req_t * req,const i2c_addr_t * addr)67*32002227SRobert Mustacchi i2c_device_add_req_set_addr(i2c_dev_add_req_t *req, const i2c_addr_t *addr)
68*32002227SRobert Mustacchi {
69*32002227SRobert Mustacchi int ret;
70*32002227SRobert Mustacchi i2c_hdl_t *hdl = req->add_port->port_hdl;
71*32002227SRobert Mustacchi
72*32002227SRobert Mustacchi if (addr == NULL) {
73*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
74*32002227SRobert Mustacchi "invalid i2c_addr_t pointer: %p", addr));
75*32002227SRobert Mustacchi }
76*32002227SRobert Mustacchi
77*32002227SRobert Mustacchi if (!i2c_addr_validate(hdl, addr)) {
78*32002227SRobert Mustacchi return (false);
79*32002227SRobert Mustacchi }
80*32002227SRobert Mustacchi
81*32002227SRobert Mustacchi ret = nvlist_add_uint16(req->add_nvl, UI2C_IOCTL_NVL_TYPE,
82*32002227SRobert Mustacchi addr->ia_type);
83*32002227SRobert Mustacchi if (!i2c_nvlist_error(hdl, ret, "insert address type")) {
84*32002227SRobert Mustacchi return (false);
85*32002227SRobert Mustacchi }
86*32002227SRobert Mustacchi
87*32002227SRobert Mustacchi ret = nvlist_add_uint16(req->add_nvl, UI2C_IOCTL_NVL_ADDR,
88*32002227SRobert Mustacchi addr->ia_addr);
89*32002227SRobert Mustacchi if (!i2c_nvlist_error(hdl, ret, "insert address type")) {
90*32002227SRobert Mustacchi return (false);
91*32002227SRobert Mustacchi }
92*32002227SRobert Mustacchi
93*32002227SRobert Mustacchi req->add_need &= ~I2C_DEV_ADD_REQ_FIELD_ADDR;
94*32002227SRobert Mustacchi return (i2c_success(hdl));
95*32002227SRobert Mustacchi }
96*32002227SRobert Mustacchi
97*32002227SRobert Mustacchi bool
i2c_device_add_req_set_name(i2c_dev_add_req_t * req,const char * name)98*32002227SRobert Mustacchi i2c_device_add_req_set_name(i2c_dev_add_req_t *req, const char *name)
99*32002227SRobert Mustacchi {
100*32002227SRobert Mustacchi i2c_hdl_t *hdl = req->add_port->port_hdl;
101*32002227SRobert Mustacchi
102*32002227SRobert Mustacchi if (!i2c_name_validate(hdl, name, "name")) {
103*32002227SRobert Mustacchi return (false);
104*32002227SRobert Mustacchi }
105*32002227SRobert Mustacchi
106*32002227SRobert Mustacchi int ret = nvlist_add_string(req->add_nvl, UI2C_IOCTL_NVL_NAME, name);
107*32002227SRobert Mustacchi if (!i2c_nvlist_error(hdl, ret, "insert name string")) {
108*32002227SRobert Mustacchi return (false);
109*32002227SRobert Mustacchi }
110*32002227SRobert Mustacchi
111*32002227SRobert Mustacchi req->add_need &= ~I2C_DEV_ADD_REQ_FIELD_NAME;
112*32002227SRobert Mustacchi return (i2c_success(hdl));
113*32002227SRobert Mustacchi }
114*32002227SRobert Mustacchi
115*32002227SRobert Mustacchi bool
i2c_device_add_req_set_compatible(i2c_dev_add_req_t * req,char * const * compat,size_t ncompat)116*32002227SRobert Mustacchi i2c_device_add_req_set_compatible(i2c_dev_add_req_t *req, char *const *compat,
117*32002227SRobert Mustacchi size_t ncompat)
118*32002227SRobert Mustacchi {
119*32002227SRobert Mustacchi i2c_hdl_t *hdl = req->add_port->port_hdl;
120*32002227SRobert Mustacchi
121*32002227SRobert Mustacchi /*
122*32002227SRobert Mustacchi * Treat this as a request to clear the optional compatible information.
123*32002227SRobert Mustacchi */
124*32002227SRobert Mustacchi if (compat == NULL && ncompat == 0) {
125*32002227SRobert Mustacchi int ret = nvlist_remove(req->add_nvl, UI2C_IOCTL_NVL_COMPAT,
126*32002227SRobert Mustacchi DATA_TYPE_STRING_ARRAY);
127*32002227SRobert Mustacchi if (ret == 0 || ret == ENOENT) {
128*32002227SRobert Mustacchi return (i2c_success(hdl));
129*32002227SRobert Mustacchi }
130*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_INTERNAL, ret, "unexpected "
131*32002227SRobert Mustacchi "internal error while trying to clear compatible[]"));
132*32002227SRobert Mustacchi }
133*32002227SRobert Mustacchi
134*32002227SRobert Mustacchi if (compat == NULL) {
135*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
136*32002227SRobert Mustacchi "invalid compatible pointer: %p", compat));
137*32002227SRobert Mustacchi } else if (ncompat == 0) {
138*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_COMPAT_LEN_RANGE, 0, "number "
139*32002227SRobert Mustacchi "of compatible entries cannot be zero when given a "
140*32002227SRobert Mustacchi "non-NULL pointer (%p)", compat));
141*32002227SRobert Mustacchi } else if (ncompat > UI2C_IOCTL_NVL_NCOMPAT_MAX) {
142*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_COMPAT_LEN_RANGE, 0, "device "
143*32002227SRobert Mustacchi "compatible array is too long (%zu), valid range is [1, "
144*32002227SRobert Mustacchi "%u]", ncompat, UI2C_IOCTL_NVL_NCOMPAT_MAX));
145*32002227SRobert Mustacchi }
146*32002227SRobert Mustacchi
147*32002227SRobert Mustacchi for (size_t i = 0; i < ncompat; i++) {
148*32002227SRobert Mustacchi char desc[64];
149*32002227SRobert Mustacchi
150*32002227SRobert Mustacchi (void) snprintf(desc, sizeof (desc), "compatible[%u]", i);
151*32002227SRobert Mustacchi if (!i2c_name_validate(hdl, compat[i], desc)) {
152*32002227SRobert Mustacchi return (false);
153*32002227SRobert Mustacchi }
154*32002227SRobert Mustacchi }
155*32002227SRobert Mustacchi
156*32002227SRobert Mustacchi int ret = nvlist_add_string_array(req->add_nvl, UI2C_IOCTL_NVL_COMPAT,
157*32002227SRobert Mustacchi compat, ncompat);
158*32002227SRobert Mustacchi if (!i2c_nvlist_error(hdl, ret, "insert compatible string[]")) {
159*32002227SRobert Mustacchi return (false);
160*32002227SRobert Mustacchi }
161*32002227SRobert Mustacchi return (i2c_success(hdl));
162*32002227SRobert Mustacchi }
163*32002227SRobert Mustacchi
164*32002227SRobert Mustacchi bool
i2c_device_add_req_exec(i2c_dev_add_req_t * req)165*32002227SRobert Mustacchi i2c_device_add_req_exec(i2c_dev_add_req_t *req)
166*32002227SRobert Mustacchi {
167*32002227SRobert Mustacchi i2c_hdl_t *hdl = req->add_port->port_hdl;
168*32002227SRobert Mustacchi size_t pack_size;
169*32002227SRobert Mustacchi char *pack_buf = NULL;
170*32002227SRobert Mustacchi int nvl_ret;
171*32002227SRobert Mustacchi bool ret = false;
172*32002227SRobert Mustacchi ui2c_dev_add_t dev;
173*32002227SRobert Mustacchi
174*32002227SRobert Mustacchi if (req->add_need != 0) {
175*32002227SRobert Mustacchi char buf[128];
176*32002227SRobert Mustacchi bool comma = false;
177*32002227SRobert Mustacchi
178*32002227SRobert Mustacchi buf[0] = '\0';
179*32002227SRobert Mustacchi if ((req->add_need & I2C_DEV_ADD_REQ_FIELD_ADDR) != 0) {
180*32002227SRobert Mustacchi (void) strlcat(buf, "device address", sizeof (buf));
181*32002227SRobert Mustacchi comma = true;
182*32002227SRobert Mustacchi }
183*32002227SRobert Mustacchi
184*32002227SRobert Mustacchi if ((req->add_need & I2C_DEV_ADD_REQ_FIELD_NAME) != 0) {
185*32002227SRobert Mustacchi if (comma) {
186*32002227SRobert Mustacchi (void) strlcat(buf, ",", sizeof (buf));
187*32002227SRobert Mustacchi }
188*32002227SRobert Mustacchi (void) strlcat(buf, "name", sizeof (buf));
189*32002227SRobert Mustacchi comma = true;
190*32002227SRobert Mustacchi }
191*32002227SRobert Mustacchi
192*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_ADD_DEV_REQ_MISSING_FIELDS, 0,
193*32002227SRobert Mustacchi "cannot execute add device request due to missing fields: "
194*32002227SRobert Mustacchi "%s", buf));
195*32002227SRobert Mustacchi }
196*32002227SRobert Mustacchi
197*32002227SRobert Mustacchi nvl_ret = nvlist_size(req->add_nvl, &pack_size, NV_ENCODE_NATIVE);
198*32002227SRobert Mustacchi if (!i2c_nvlist_error(hdl, nvl_ret, "determine packed nvlist size")) {
199*32002227SRobert Mustacchi goto out;
200*32002227SRobert Mustacchi }
201*32002227SRobert Mustacchi
202*32002227SRobert Mustacchi pack_buf = malloc(pack_size);
203*32002227SRobert Mustacchi if (pack_buf == NULL) {
204*32002227SRobert Mustacchi ret = i2c_error(hdl, I2C_ERR_NO_MEM, errno, "failed to "
205*32002227SRobert Mustacchi "allocate %zu bytes for packed request nvlist", pack_size);
206*32002227SRobert Mustacchi goto out;
207*32002227SRobert Mustacchi }
208*32002227SRobert Mustacchi
209*32002227SRobert Mustacchi nvl_ret = nvlist_pack(req->add_nvl, &pack_buf, &pack_size,
210*32002227SRobert Mustacchi NV_ENCODE_NATIVE, 0);
211*32002227SRobert Mustacchi if (!i2c_nvlist_error(hdl, nvl_ret, "pack request nvlist")) {
212*32002227SRobert Mustacchi goto out;
213*32002227SRobert Mustacchi }
214*32002227SRobert Mustacchi
215*32002227SRobert Mustacchi (void) memset(&dev, 0, sizeof (ui2c_dev_add_t));
216*32002227SRobert Mustacchi dev.uda_nvl = (uintptr_t)pack_buf;
217*32002227SRobert Mustacchi dev.uda_nvl_len = pack_size;
218*32002227SRobert Mustacchi
219*32002227SRobert Mustacchi if (ioctl(req->add_port->port_fd, UI2C_IOCTL_DEVICE_ADD, &dev) != 0) {
220*32002227SRobert Mustacchi int e = errno;
221*32002227SRobert Mustacchi ret = i2c_ioctl_syserror(hdl, e, "add device request");
222*32002227SRobert Mustacchi goto out;
223*32002227SRobert Mustacchi }
224*32002227SRobert Mustacchi
225*32002227SRobert Mustacchi if (dev.uda_error.i2c_error != I2C_CORE_E_OK) {
226*32002227SRobert Mustacchi ret = i2c_ioctl_error(hdl, &dev.uda_error,
227*32002227SRobert Mustacchi "add device request");
228*32002227SRobert Mustacchi goto out;
229*32002227SRobert Mustacchi }
230*32002227SRobert Mustacchi
231*32002227SRobert Mustacchi ret = i2c_success(hdl);
232*32002227SRobert Mustacchi out:
233*32002227SRobert Mustacchi free(pack_buf);
234*32002227SRobert Mustacchi return (ret);
235*32002227SRobert Mustacchi }
236*32002227SRobert Mustacchi
237*32002227SRobert Mustacchi bool
i2c_device_rem(i2c_port_t * port,const i2c_addr_t * addr)238*32002227SRobert Mustacchi i2c_device_rem(i2c_port_t *port, const i2c_addr_t *addr)
239*32002227SRobert Mustacchi {
240*32002227SRobert Mustacchi ui2c_dev_rem_t rem;
241*32002227SRobert Mustacchi i2c_hdl_t *hdl = port->port_hdl;
242*32002227SRobert Mustacchi
243*32002227SRobert Mustacchi if (addr == NULL) {
244*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
245*32002227SRobert Mustacchi "invalid i2c_addr_t pointer: %p", addr));
246*32002227SRobert Mustacchi }
247*32002227SRobert Mustacchi
248*32002227SRobert Mustacchi if (!i2c_addr_validate(hdl, addr)) {
249*32002227SRobert Mustacchi return (false);
250*32002227SRobert Mustacchi }
251*32002227SRobert Mustacchi
252*32002227SRobert Mustacchi (void) memset(&rem, 0, sizeof (ui2c_dev_rem_t));
253*32002227SRobert Mustacchi rem.udr_addr = *addr;
254*32002227SRobert Mustacchi
255*32002227SRobert Mustacchi if (ioctl(port->port_fd, UI2C_IOCTL_DEVICE_REMOVE, &rem) != 0) {
256*32002227SRobert Mustacchi int e = errno;
257*32002227SRobert Mustacchi return (i2c_ioctl_syserror(hdl, e, "remove device request"));
258*32002227SRobert Mustacchi }
259*32002227SRobert Mustacchi
260*32002227SRobert Mustacchi if (rem.udr_error.i2c_error != I2C_CORE_E_OK) {
261*32002227SRobert Mustacchi return (i2c_ioctl_error(hdl, &rem.udr_error,
262*32002227SRobert Mustacchi "remove device request"));
263*32002227SRobert Mustacchi }
264*32002227SRobert Mustacchi
265*32002227SRobert Mustacchi return (i2c_success(hdl));
266*32002227SRobert Mustacchi }
267*32002227SRobert Mustacchi
268*32002227SRobert Mustacchi void
i2c_device_discover_fini(i2c_dev_iter_t * iter)269*32002227SRobert Mustacchi i2c_device_discover_fini(i2c_dev_iter_t *iter)
270*32002227SRobert Mustacchi {
271*32002227SRobert Mustacchi if (iter == NULL)
272*32002227SRobert Mustacchi return;
273*32002227SRobert Mustacchi
274*32002227SRobert Mustacchi i2c_port_discover_fini(iter->di_iter);
275*32002227SRobert Mustacchi free(iter);
276*32002227SRobert Mustacchi }
277*32002227SRobert Mustacchi
278*32002227SRobert Mustacchi /*
279*32002227SRobert Mustacchi * Fill information about the device's under this single port per the notes in
280*32002227SRobert Mustacchi * i2c_device_discover_step().
281*32002227SRobert Mustacchi */
282*32002227SRobert Mustacchi static bool
i2c_device_discover_port(i2c_hdl_t * hdl,dev_port_info_t * dpi)283*32002227SRobert Mustacchi i2c_device_discover_port(i2c_hdl_t *hdl, dev_port_info_t *dpi)
284*32002227SRobert Mustacchi {
285*32002227SRobert Mustacchi for (di_minor_t m = di_minor_next(dpi->dpi_port, DI_MINOR_NIL);
286*32002227SRobert Mustacchi m != DI_MINOR_NIL; m = di_minor_next(dpi->dpi_port, m)) {
287*32002227SRobert Mustacchi i2c_addr_t addr;
288*32002227SRobert Mustacchi
289*32002227SRobert Mustacchi if (strcmp(di_minor_nodetype(m), DDI_NT_I2C_DEV) != 0)
290*32002227SRobert Mustacchi continue;
291*32002227SRobert Mustacchi
292*32002227SRobert Mustacchi if (!i2c_kernel_address_parse(hdl, di_minor_name(m), &addr)) {
293*32002227SRobert Mustacchi return (false);
294*32002227SRobert Mustacchi }
295*32002227SRobert Mustacchi
296*32002227SRobert Mustacchi if (addr.ia_type == I2C_ADDR_7BIT) {
297*32002227SRobert Mustacchi dpi->dpi_7b[addr.ia_addr].dmi_minor = m;
298*32002227SRobert Mustacchi } else {
299*32002227SRobert Mustacchi dpi->dpi_10b[addr.ia_addr].dmi_minor = m;
300*32002227SRobert Mustacchi }
301*32002227SRobert Mustacchi }
302*32002227SRobert Mustacchi
303*32002227SRobert Mustacchi /*
304*32002227SRobert Mustacchi * Now go through all of our children and try to map them to something
305*32002227SRobert Mustacchi * we know.
306*32002227SRobert Mustacchi */
307*32002227SRobert Mustacchi for (di_node_t di = di_child_node(dpi->dpi_port); di != DI_NODE_NIL;
308*32002227SRobert Mustacchi di = di_sibling_node(di)) {
309*32002227SRobert Mustacchi i2c_addr_t addr;
310*32002227SRobert Mustacchi
311*32002227SRobert Mustacchi if (i2c_node_type(di) != I2C_NODE_T_DEV) {
312*32002227SRobert Mustacchi continue;
313*32002227SRobert Mustacchi }
314*32002227SRobert Mustacchi
315*32002227SRobert Mustacchi /*
316*32002227SRobert Mustacchi * For the purposes of iteration we order devices by the first
317*32002227SRobert Mustacchi * address that they have in their regs[] array. We assume that
318*32002227SRobert Mustacchi * this will be the primary one. We will skip cases where we
319*32002227SRobert Mustacchi * have a minor but not a devinfo in this list.
320*32002227SRobert Mustacchi */
321*32002227SRobert Mustacchi if (!i2c_reg_to_addr(hdl, di, &addr, 0)) {
322*32002227SRobert Mustacchi return (false);
323*32002227SRobert Mustacchi }
324*32002227SRobert Mustacchi
325*32002227SRobert Mustacchi if (addr.ia_type == I2C_ADDR_7BIT) {
326*32002227SRobert Mustacchi dpi->dpi_7b[addr.ia_addr].dmi_node = di;
327*32002227SRobert Mustacchi } else {
328*32002227SRobert Mustacchi dpi->dpi_10b[addr.ia_addr].dmi_node = di;
329*32002227SRobert Mustacchi }
330*32002227SRobert Mustacchi }
331*32002227SRobert Mustacchi
332*32002227SRobert Mustacchi return (true);
333*32002227SRobert Mustacchi }
334*32002227SRobert Mustacchi
335*32002227SRobert Mustacchi static bool
i2c_device_discover_one(i2c_dev_iter_t * iter,dev_map_info_t * map)336*32002227SRobert Mustacchi i2c_device_discover_one(i2c_dev_iter_t *iter, dev_map_info_t *map)
337*32002227SRobert Mustacchi {
338*32002227SRobert Mustacchi iter->di_disc.idd_map = map;
339*32002227SRobert Mustacchi iter->di_disc.idd_port = &iter->di_info;
340*32002227SRobert Mustacchi if (!i2c_node_to_path(iter->di_hdl, map->dmi_node,
341*32002227SRobert Mustacchi iter->di_disc.idd_path, sizeof (iter->di_disc.idd_path))) {
342*32002227SRobert Mustacchi return (false);
343*32002227SRobert Mustacchi }
344*32002227SRobert Mustacchi
345*32002227SRobert Mustacchi return (true);
346*32002227SRobert Mustacchi }
347*32002227SRobert Mustacchi
348*32002227SRobert Mustacchi /*
349*32002227SRobert Mustacchi * Device discovery starts by walking the last of I2C ports. After that we
350*32002227SRobert Mustacchi * proceed to try to walk all of the immediate children. The port has a list of
351*32002227SRobert Mustacchi * all of the minors that are I2C devices. So we first gather that up and marry
352*32002227SRobert Mustacchi * it up to the actual dev_info nodes in the snapshot. The minor node will be
353*32002227SRobert Mustacchi * created while we're creating the child node and we should only see one if we
354*32002227SRobert Mustacchi * see the other. By walking the minor node list, this gives us a way to ignore
355*32002227SRobert Mustacchi * dev info nodes that end up under the port that aren't actually in-band
356*32002227SRobert Mustacchi * devices (e.g. a non-in-band mux).
357*32002227SRobert Mustacchi */
358*32002227SRobert Mustacchi i2c_iter_t
i2c_device_discover_step(i2c_dev_iter_t * iter,const i2c_dev_disc_t ** discp)359*32002227SRobert Mustacchi i2c_device_discover_step(i2c_dev_iter_t *iter, const i2c_dev_disc_t **discp)
360*32002227SRobert Mustacchi {
361*32002227SRobert Mustacchi for (;;) {
362*32002227SRobert Mustacchi /*
363*32002227SRobert Mustacchi * First check if we're already done or if we're taking a lap
364*32002227SRobert Mustacchi * because we've processed all ports.
365*32002227SRobert Mustacchi */
366*32002227SRobert Mustacchi if (iter->di_done) {
367*32002227SRobert Mustacchi return (I2C_ITER_DONE);
368*32002227SRobert Mustacchi }
369*32002227SRobert Mustacchi
370*32002227SRobert Mustacchi if (iter->di_curport == NULL) {
371*32002227SRobert Mustacchi i2c_iter_t iret = i2c_port_discover_step(iter->di_iter,
372*32002227SRobert Mustacchi &iter->di_curport);
373*32002227SRobert Mustacchi if (iret == I2C_ITER_DONE) {
374*32002227SRobert Mustacchi iter->di_done = true;
375*32002227SRobert Mustacchi return (I2C_ITER_DONE);
376*32002227SRobert Mustacchi } else if (iret != I2C_ITER_VALID) {
377*32002227SRobert Mustacchi return (iret);
378*32002227SRobert Mustacchi }
379*32002227SRobert Mustacchi
380*32002227SRobert Mustacchi memset(&iter->di_info, 0, sizeof (dev_port_info_t));
381*32002227SRobert Mustacchi iter->di_info.dpi_port =
382*32002227SRobert Mustacchi i2c_port_disc_devi(iter->di_curport);
383*32002227SRobert Mustacchi }
384*32002227SRobert Mustacchi
385*32002227SRobert Mustacchi /*
386*32002227SRobert Mustacchi * See if we have minor info for this port yet. If not, we go
387*32002227SRobert Mustacchi * and build it.
388*32002227SRobert Mustacchi */
389*32002227SRobert Mustacchi dev_port_info_t *pi = &iter->di_info;
390*32002227SRobert Mustacchi if (!pi->dpi_scanned) {
391*32002227SRobert Mustacchi pi->dpi_scanned = true;
392*32002227SRobert Mustacchi if (!i2c_device_discover_port(iter->di_hdl, pi)) {
393*32002227SRobert Mustacchi return (I2C_ITER_ERROR);
394*32002227SRobert Mustacchi }
395*32002227SRobert Mustacchi }
396*32002227SRobert Mustacchi
397*32002227SRobert Mustacchi /*
398*32002227SRobert Mustacchi * Is this port done, if so move onto the next.
399*32002227SRobert Mustacchi */
400*32002227SRobert Mustacchi if (pi->dpi_7bit_done && pi->dpi_10bit_done) {
401*32002227SRobert Mustacchi iter->di_curport = NULL;
402*32002227SRobert Mustacchi continue;
403*32002227SRobert Mustacchi }
404*32002227SRobert Mustacchi
405*32002227SRobert Mustacchi if (!pi->dpi_7bit_done) {
406*32002227SRobert Mustacchi while (pi->dpi_curidx < ARRAY_SIZE(pi->dpi_7b)) {
407*32002227SRobert Mustacchi dev_map_info_t *map =
408*32002227SRobert Mustacchi &pi->dpi_7b[pi->dpi_curidx];
409*32002227SRobert Mustacchi pi->dpi_curidx++;
410*32002227SRobert Mustacchi if (map->dmi_minor == DI_MINOR_NIL ||
411*32002227SRobert Mustacchi map->dmi_node == DI_NODE_NIL) {
412*32002227SRobert Mustacchi continue;
413*32002227SRobert Mustacchi }
414*32002227SRobert Mustacchi
415*32002227SRobert Mustacchi if (i2c_device_discover_one(iter, map)) {
416*32002227SRobert Mustacchi *discp = &iter->di_disc;
417*32002227SRobert Mustacchi return (I2C_ITER_VALID);
418*32002227SRobert Mustacchi } else {
419*32002227SRobert Mustacchi return (I2C_ITER_ERROR);
420*32002227SRobert Mustacchi }
421*32002227SRobert Mustacchi }
422*32002227SRobert Mustacchi pi->dpi_7bit_done = true;
423*32002227SRobert Mustacchi pi->dpi_curidx = 0;
424*32002227SRobert Mustacchi }
425*32002227SRobert Mustacchi
426*32002227SRobert Mustacchi
427*32002227SRobert Mustacchi if (!pi->dpi_10bit_done) {
428*32002227SRobert Mustacchi while (pi->dpi_curidx < ARRAY_SIZE(pi->dpi_10b)) {
429*32002227SRobert Mustacchi dev_map_info_t *map =
430*32002227SRobert Mustacchi &pi->dpi_10b[pi->dpi_curidx];
431*32002227SRobert Mustacchi pi->dpi_curidx++;
432*32002227SRobert Mustacchi if (map->dmi_minor == DI_MINOR_NIL ||
433*32002227SRobert Mustacchi map->dmi_node == DI_NODE_NIL) {
434*32002227SRobert Mustacchi continue;
435*32002227SRobert Mustacchi }
436*32002227SRobert Mustacchi
437*32002227SRobert Mustacchi if (i2c_device_discover_one(iter, map)) {
438*32002227SRobert Mustacchi *discp = &iter->di_disc;
439*32002227SRobert Mustacchi return (I2C_ITER_VALID);
440*32002227SRobert Mustacchi } else {
441*32002227SRobert Mustacchi return (I2C_ITER_ERROR);
442*32002227SRobert Mustacchi }
443*32002227SRobert Mustacchi }
444*32002227SRobert Mustacchi pi->dpi_10bit_done = true;
445*32002227SRobert Mustacchi pi->dpi_curidx = 0;
446*32002227SRobert Mustacchi }
447*32002227SRobert Mustacchi }
448*32002227SRobert Mustacchi
449*32002227SRobert Mustacchi return (I2C_ITER_ERROR);
450*32002227SRobert Mustacchi }
451*32002227SRobert Mustacchi
452*32002227SRobert Mustacchi bool
i2c_device_discover_init(i2c_hdl_t * hdl,i2c_dev_iter_t ** iterp)453*32002227SRobert Mustacchi i2c_device_discover_init(i2c_hdl_t *hdl, i2c_dev_iter_t **iterp)
454*32002227SRobert Mustacchi {
455*32002227SRobert Mustacchi i2c_dev_iter_t *iter;
456*32002227SRobert Mustacchi
457*32002227SRobert Mustacchi if (iterp == NULL) {
458*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
459*32002227SRobert Mustacchi "invalid i2c_dev_iter_t output pointer: %p", iterp));
460*32002227SRobert Mustacchi }
461*32002227SRobert Mustacchi
462*32002227SRobert Mustacchi iter = calloc(1, sizeof (i2c_dev_iter_t));
463*32002227SRobert Mustacchi if (iter == NULL) {
464*32002227SRobert Mustacchi int e = errno;
465*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
466*32002227SRobert Mustacchi "memory for a new i2c_dev_iter_t"));
467*32002227SRobert Mustacchi }
468*32002227SRobert Mustacchi
469*32002227SRobert Mustacchi iter->di_hdl = hdl;
470*32002227SRobert Mustacchi iter->di_done = false;
471*32002227SRobert Mustacchi if (!i2c_port_discover_init(hdl, &iter->di_iter)) {
472*32002227SRobert Mustacchi free(iter);
473*32002227SRobert Mustacchi return (false);
474*32002227SRobert Mustacchi }
475*32002227SRobert Mustacchi
476*32002227SRobert Mustacchi *iterp = iter;
477*32002227SRobert Mustacchi return (i2c_success(hdl));
478*32002227SRobert Mustacchi }
479*32002227SRobert Mustacchi
480*32002227SRobert Mustacchi bool
i2c_device_discover(i2c_hdl_t * hdl,i2c_dev_disc_f func,void * arg)481*32002227SRobert Mustacchi i2c_device_discover(i2c_hdl_t *hdl, i2c_dev_disc_f func, void *arg)
482*32002227SRobert Mustacchi {
483*32002227SRobert Mustacchi i2c_dev_iter_t *iter;
484*32002227SRobert Mustacchi const i2c_dev_disc_t *disc;
485*32002227SRobert Mustacchi i2c_iter_t ret;
486*32002227SRobert Mustacchi
487*32002227SRobert Mustacchi if (func == NULL) {
488*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
489*32002227SRobert Mustacchi "invalid i2c_dev_disc_f function pointer: %p", func));
490*32002227SRobert Mustacchi }
491*32002227SRobert Mustacchi
492*32002227SRobert Mustacchi if (!i2c_device_discover_init(hdl, &iter)) {
493*32002227SRobert Mustacchi return (false);
494*32002227SRobert Mustacchi }
495*32002227SRobert Mustacchi
496*32002227SRobert Mustacchi while ((ret = i2c_device_discover_step(iter, &disc)) ==
497*32002227SRobert Mustacchi I2C_ITER_VALID) {
498*32002227SRobert Mustacchi if (!func(hdl, disc, arg))
499*32002227SRobert Mustacchi break;
500*32002227SRobert Mustacchi }
501*32002227SRobert Mustacchi
502*32002227SRobert Mustacchi i2c_device_discover_fini(iter);
503*32002227SRobert Mustacchi if (ret == I2C_ITER_ERROR) {
504*32002227SRobert Mustacchi return (false);
505*32002227SRobert Mustacchi }
506*32002227SRobert Mustacchi
507*32002227SRobert Mustacchi return (i2c_success(hdl));
508*32002227SRobert Mustacchi }
509*32002227SRobert Mustacchi
510*32002227SRobert Mustacchi const char *
i2c_device_disc_name(const i2c_dev_disc_t * disc)511*32002227SRobert Mustacchi i2c_device_disc_name(const i2c_dev_disc_t *disc)
512*32002227SRobert Mustacchi {
513*32002227SRobert Mustacchi return (di_node_name(disc->idd_map->dmi_node));
514*32002227SRobert Mustacchi }
515*32002227SRobert Mustacchi
516*32002227SRobert Mustacchi di_node_t
i2c_device_disc_devi(const i2c_dev_disc_t * disc)517*32002227SRobert Mustacchi i2c_device_disc_devi(const i2c_dev_disc_t *disc)
518*32002227SRobert Mustacchi {
519*32002227SRobert Mustacchi return (disc->idd_map->dmi_node);
520*32002227SRobert Mustacchi }
521*32002227SRobert Mustacchi
522*32002227SRobert Mustacchi di_minor_t
i2c_device_disc_devctl(const i2c_dev_disc_t * disc)523*32002227SRobert Mustacchi i2c_device_disc_devctl(const i2c_dev_disc_t *disc)
524*32002227SRobert Mustacchi {
525*32002227SRobert Mustacchi return (disc->idd_map->dmi_minor);
526*32002227SRobert Mustacchi }
527*32002227SRobert Mustacchi
528*32002227SRobert Mustacchi const char *
i2c_device_disc_path(const i2c_dev_disc_t * disc)529*32002227SRobert Mustacchi i2c_device_disc_path(const i2c_dev_disc_t *disc)
530*32002227SRobert Mustacchi {
531*32002227SRobert Mustacchi return (disc->idd_path);
532*32002227SRobert Mustacchi }
533*32002227SRobert Mustacchi
534*32002227SRobert Mustacchi void
i2c_device_info_free(i2c_dev_info_t * info)535*32002227SRobert Mustacchi i2c_device_info_free(i2c_dev_info_t *info)
536*32002227SRobert Mustacchi {
537*32002227SRobert Mustacchi free(info->dinfo_name);
538*32002227SRobert Mustacchi free(info->dinfo_driver);
539*32002227SRobert Mustacchi free(info->dinfo_addrs);
540*32002227SRobert Mustacchi di_devfs_path_free(info->dinfo_minor);
541*32002227SRobert Mustacchi free(info);
542*32002227SRobert Mustacchi }
543*32002227SRobert Mustacchi
544*32002227SRobert Mustacchi const char *
i2c_device_info_path(const i2c_dev_info_t * info)545*32002227SRobert Mustacchi i2c_device_info_path(const i2c_dev_info_t *info)
546*32002227SRobert Mustacchi {
547*32002227SRobert Mustacchi return (info->dinfo_path);
548*32002227SRobert Mustacchi }
549*32002227SRobert Mustacchi
550*32002227SRobert Mustacchi const char *
i2c_device_info_name(const i2c_dev_info_t * info)551*32002227SRobert Mustacchi i2c_device_info_name(const i2c_dev_info_t *info)
552*32002227SRobert Mustacchi {
553*32002227SRobert Mustacchi return (info->dinfo_name);
554*32002227SRobert Mustacchi }
555*32002227SRobert Mustacchi
556*32002227SRobert Mustacchi const char *
i2c_device_info_driver(const i2c_dev_info_t * info)557*32002227SRobert Mustacchi i2c_device_info_driver(const i2c_dev_info_t *info)
558*32002227SRobert Mustacchi {
559*32002227SRobert Mustacchi return (info->dinfo_driver);
560*32002227SRobert Mustacchi }
561*32002227SRobert Mustacchi
562*32002227SRobert Mustacchi int
i2c_device_info_instance(const i2c_dev_info_t * info)563*32002227SRobert Mustacchi i2c_device_info_instance(const i2c_dev_info_t *info)
564*32002227SRobert Mustacchi {
565*32002227SRobert Mustacchi return (info->dinfo_inst);
566*32002227SRobert Mustacchi }
567*32002227SRobert Mustacchi
568*32002227SRobert Mustacchi uint32_t
i2c_device_info_naddrs(const i2c_dev_info_t * info)569*32002227SRobert Mustacchi i2c_device_info_naddrs(const i2c_dev_info_t *info)
570*32002227SRobert Mustacchi {
571*32002227SRobert Mustacchi return (info->dinfo_naddrs);
572*32002227SRobert Mustacchi }
573*32002227SRobert Mustacchi
574*32002227SRobert Mustacchi const i2c_addr_t *
i2c_device_info_addr_primary(const i2c_dev_info_t * info)575*32002227SRobert Mustacchi i2c_device_info_addr_primary(const i2c_dev_info_t *info)
576*32002227SRobert Mustacchi {
577*32002227SRobert Mustacchi return (&info->dinfo_info.udi_primary);
578*32002227SRobert Mustacchi }
579*32002227SRobert Mustacchi
580*32002227SRobert Mustacchi const i2c_addr_t *
i2c_device_info_addr(const i2c_dev_info_t * info,uint32_t n)581*32002227SRobert Mustacchi i2c_device_info_addr(const i2c_dev_info_t *info, uint32_t n)
582*32002227SRobert Mustacchi {
583*32002227SRobert Mustacchi if (n >= info->dinfo_naddrs) {
584*32002227SRobert Mustacchi return (NULL);
585*32002227SRobert Mustacchi }
586*32002227SRobert Mustacchi
587*32002227SRobert Mustacchi return (&info->dinfo_addrs[n]);
588*32002227SRobert Mustacchi }
589*32002227SRobert Mustacchi
590*32002227SRobert Mustacchi i2c_addr_source_t
i2c_device_info_addr_source(const i2c_dev_info_t * info,uint32_t n)591*32002227SRobert Mustacchi i2c_device_info_addr_source(const i2c_dev_info_t *info, uint32_t n)
592*32002227SRobert Mustacchi {
593*32002227SRobert Mustacchi if (n >= info->dinfo_naddrs) {
594*32002227SRobert Mustacchi return (0);
595*32002227SRobert Mustacchi }
596*32002227SRobert Mustacchi
597*32002227SRobert Mustacchi return (info->dinfo_info.udi_7b[info->dinfo_addrs[n].ia_addr]);
598*32002227SRobert Mustacchi }
599*32002227SRobert Mustacchi
600*32002227SRobert Mustacchi bool
i2c_device_info_snap(i2c_hdl_t * hdl,di_node_t dn,i2c_dev_info_t ** infop)601*32002227SRobert Mustacchi i2c_device_info_snap(i2c_hdl_t *hdl, di_node_t dn, i2c_dev_info_t **infop)
602*32002227SRobert Mustacchi {
603*32002227SRobert Mustacchi di_minor_t minor;
604*32002227SRobert Mustacchi i2c_dev_info_t *info;
605*32002227SRobert Mustacchi
606*32002227SRobert Mustacchi if (dn == DI_NODE_NIL) {
607*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
608*32002227SRobert Mustacchi "invalid di_node_t: %p", dn));
609*32002227SRobert Mustacchi }
610*32002227SRobert Mustacchi
611*32002227SRobert Mustacchi if (infop == NULL) {
612*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
613*32002227SRobert Mustacchi "invalid i2c_dev_info_t output pointer: %p", infop));
614*32002227SRobert Mustacchi }
615*32002227SRobert Mustacchi
616*32002227SRobert Mustacchi if (!i2c_node_is_type(dn, I2C_NODE_T_DEV)) {
617*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVI, 0, "devi %s@%s is "
618*32002227SRobert Mustacchi "not an i2c device", di_node_name(dn), di_bus_addr(dn)));
619*32002227SRobert Mustacchi }
620*32002227SRobert Mustacchi
621*32002227SRobert Mustacchi minor = i2c_node_minor(dn);
622*32002227SRobert Mustacchi if (minor == DI_MINOR_NIL) {
623*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVI, 0, "devi %s@%s is "
624*32002227SRobert Mustacchi "not an i2c device: failed to find device minor",
625*32002227SRobert Mustacchi di_node_name(dn), di_bus_addr(dn)));
626*32002227SRobert Mustacchi }
627*32002227SRobert Mustacchi
628*32002227SRobert Mustacchi info = calloc(1, sizeof (i2c_dev_info_t));
629*32002227SRobert Mustacchi info->dinfo_name = strdup(di_node_name(dn));
630*32002227SRobert Mustacchi if (info->dinfo_name == NULL) {
631*32002227SRobert Mustacchi int e = errno;
632*32002227SRobert Mustacchi i2c_device_info_free(info);
633*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to duplicate "
634*32002227SRobert Mustacchi "device node name"));
635*32002227SRobert Mustacchi }
636*32002227SRobert Mustacchi
637*32002227SRobert Mustacchi if (!i2c_node_to_path(hdl, dn, info->dinfo_path,
638*32002227SRobert Mustacchi sizeof (info->dinfo_path))) {
639*32002227SRobert Mustacchi i2c_device_info_free(info);
640*32002227SRobert Mustacchi return (false);
641*32002227SRobert Mustacchi }
642*32002227SRobert Mustacchi
643*32002227SRobert Mustacchi if (di_driver_name(dn) != NULL) {
644*32002227SRobert Mustacchi info->dinfo_driver = strdup(di_driver_name(dn));
645*32002227SRobert Mustacchi if (info->dinfo_driver == NULL) {
646*32002227SRobert Mustacchi int e = errno;
647*32002227SRobert Mustacchi i2c_device_info_free(info);
648*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to "
649*32002227SRobert Mustacchi "duplicate device driver name"));
650*32002227SRobert Mustacchi }
651*32002227SRobert Mustacchi } else {
652*32002227SRobert Mustacchi info->dinfo_driver = NULL;
653*32002227SRobert Mustacchi }
654*32002227SRobert Mustacchi info->dinfo_inst = di_instance(dn);
655*32002227SRobert Mustacchi info->dinfo_minor = di_devfs_minor_path(minor);
656*32002227SRobert Mustacchi if (info->dinfo_minor == NULL) {
657*32002227SRobert Mustacchi int e = errno;
658*32002227SRobert Mustacchi i2c_device_info_free(info);
659*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
660*32002227SRobert Mustacchi "obtain devices's devfs path: %s", strerrordesc_np(e)));
661*32002227SRobert Mustacchi }
662*32002227SRobert Mustacchi
663*32002227SRobert Mustacchi int fd = openat(hdl->ih_devfd, info->dinfo_minor + 1, O_RDONLY);
664*32002227SRobert Mustacchi if (fd < 0) {
665*32002227SRobert Mustacchi int e = errno;
666*32002227SRobert Mustacchi (void) i2c_error(hdl, I2C_ERR_OPEN_DEV, e, "failed to open "
667*32002227SRobert Mustacchi "device path /devices%s: %s", info->dinfo_minor,
668*32002227SRobert Mustacchi strerrordesc_np(e));
669*32002227SRobert Mustacchi i2c_device_info_free(info);
670*32002227SRobert Mustacchi return (false);
671*32002227SRobert Mustacchi }
672*32002227SRobert Mustacchi
673*32002227SRobert Mustacchi if (ioctl(fd, UI2C_IOCTL_DEV_INFO, &info->dinfo_info) != 0) {
674*32002227SRobert Mustacchi int e = errno;
675*32002227SRobert Mustacchi i2c_device_info_free(info);
676*32002227SRobert Mustacchi return (i2c_ioctl_syserror(hdl, e, "device information "
677*32002227SRobert Mustacchi "request"));
678*32002227SRobert Mustacchi }
679*32002227SRobert Mustacchi
680*32002227SRobert Mustacchi (void) close(fd);
681*32002227SRobert Mustacchi if (info->dinfo_info.udi_error.i2c_error != I2C_CORE_E_OK) {
682*32002227SRobert Mustacchi i2c_device_info_free(info);
683*32002227SRobert Mustacchi return (i2c_ioctl_error(hdl, &info->dinfo_info.udi_error,
684*32002227SRobert Mustacchi "device information request"));
685*32002227SRobert Mustacchi }
686*32002227SRobert Mustacchi
687*32002227SRobert Mustacchi for (uint32_t i = 0; i < ARRAY_SIZE(info->dinfo_info.udi_7b); i++) {
688*32002227SRobert Mustacchi if (info->dinfo_info.udi_7b[i] != 0) {
689*32002227SRobert Mustacchi info->dinfo_naddrs++;
690*32002227SRobert Mustacchi }
691*32002227SRobert Mustacchi }
692*32002227SRobert Mustacchi
693*32002227SRobert Mustacchi VERIFY3U(info->dinfo_naddrs, >, 0);
694*32002227SRobert Mustacchi info->dinfo_addrs = calloc(info->dinfo_naddrs, sizeof (i2c_addr_t));
695*32002227SRobert Mustacchi if (info->dinfo_addrs == NULL) {
696*32002227SRobert Mustacchi int e = errno;
697*32002227SRobert Mustacchi (void) i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
698*32002227SRobert Mustacchi "memory for %u I2C addresses", info->dinfo_naddrs);
699*32002227SRobert Mustacchi i2c_device_info_free(info);
700*32002227SRobert Mustacchi return (false);
701*32002227SRobert Mustacchi }
702*32002227SRobert Mustacchi
703*32002227SRobert Mustacchi for (uint32_t i = 0, idx = 0; i < ARRAY_SIZE(info->dinfo_info.udi_7b);
704*32002227SRobert Mustacchi i++) {
705*32002227SRobert Mustacchi if (info->dinfo_info.udi_7b[i] != 0) {
706*32002227SRobert Mustacchi info->dinfo_addrs[idx].ia_type = I2C_ADDR_7BIT;
707*32002227SRobert Mustacchi info->dinfo_addrs[idx].ia_addr = i;
708*32002227SRobert Mustacchi idx++;
709*32002227SRobert Mustacchi }
710*32002227SRobert Mustacchi }
711*32002227SRobert Mustacchi
712*32002227SRobert Mustacchi *infop = info;
713*32002227SRobert Mustacchi return (i2c_success(hdl));
714*32002227SRobert Mustacchi }
715*32002227SRobert Mustacchi
716*32002227SRobert Mustacchi /*
717*32002227SRobert Mustacchi * Get information about a device specified by path. In addition, return its
718*32002227SRobert Mustacchi * port. If nodev_ok is set to true, then our caller is fine with returning
719*32002227SRobert Mustacchi * success, but without the device information. This would happen if the path
720*32002227SRobert Mustacchi * ended at a port.
721*32002227SRobert Mustacchi */
722*32002227SRobert Mustacchi bool
i2c_port_dev_init_by_path(i2c_hdl_t * hdl,const char * path,bool nodev_ok,i2c_port_t ** portp,i2c_dev_info_t ** infop)723*32002227SRobert Mustacchi i2c_port_dev_init_by_path(i2c_hdl_t *hdl, const char *path, bool nodev_ok,
724*32002227SRobert Mustacchi i2c_port_t **portp, i2c_dev_info_t **infop)
725*32002227SRobert Mustacchi {
726*32002227SRobert Mustacchi i2c_node_type_t type;
727*32002227SRobert Mustacchi di_node_t dn, root, port_dn, dev_dn;
728*32002227SRobert Mustacchi if (path == NULL) {
729*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
730*32002227SRobert Mustacchi "invalid i2c path: %p", path));
731*32002227SRobert Mustacchi }
732*32002227SRobert Mustacchi
733*32002227SRobert Mustacchi if (portp == NULL) {
734*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
735*32002227SRobert Mustacchi "invalid i2c_port_t output pointer: %p", infop));
736*32002227SRobert Mustacchi }
737*32002227SRobert Mustacchi *portp = NULL;
738*32002227SRobert Mustacchi
739*32002227SRobert Mustacchi if (infop == NULL) {
740*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
741*32002227SRobert Mustacchi "invalid i2c_dev_info_t output pointer: %p", infop));
742*32002227SRobert Mustacchi }
743*32002227SRobert Mustacchi *infop = NULL;
744*32002227SRobert Mustacchi
745*32002227SRobert Mustacchi root = di_init("/", DINFOCPYALL);
746*32002227SRobert Mustacchi if (root == DI_NODE_NIL) {
747*32002227SRobert Mustacchi int e = errno;
748*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
749*32002227SRobert Mustacchi "initialize devinfo snapshot: %s", strerrordesc_np(e)));
750*32002227SRobert Mustacchi }
751*32002227SRobert Mustacchi
752*32002227SRobert Mustacchi if (!i2c_path_parse(hdl, path, root, &dn, &type, I2C_ERR_BAD_DEVICE)) {
753*32002227SRobert Mustacchi di_fini(root);
754*32002227SRobert Mustacchi return (false);
755*32002227SRobert Mustacchi }
756*32002227SRobert Mustacchi
757*32002227SRobert Mustacchi switch (type) {
758*32002227SRobert Mustacchi case I2C_NODE_T_DEV:
759*32002227SRobert Mustacchi dev_dn = dn;
760*32002227SRobert Mustacchi port_dn = di_parent_node(dev_dn);
761*32002227SRobert Mustacchi break;
762*32002227SRobert Mustacchi case I2C_NODE_T_PORT:
763*32002227SRobert Mustacchi if (!nodev_ok) {
764*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVICE, 0, "parsed "
765*32002227SRobert Mustacchi "I2C path %s did not end at a device", path));
766*32002227SRobert Mustacchi }
767*32002227SRobert Mustacchi dev_dn = DI_NODE_NIL;
768*32002227SRobert Mustacchi port_dn = dn;
769*32002227SRobert Mustacchi break;
770*32002227SRobert Mustacchi default:
771*32002227SRobert Mustacchi di_fini(root);
772*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVICE, 0, "parsed I2C "
773*32002227SRobert Mustacchi "path %s did not end at a device (or port)", path));
774*32002227SRobert Mustacchi }
775*32002227SRobert Mustacchi
776*32002227SRobert Mustacchi if (!i2c_port_init(hdl, port_dn, portp)) {
777*32002227SRobert Mustacchi di_fini(root);
778*32002227SRobert Mustacchi return (false);
779*32002227SRobert Mustacchi }
780*32002227SRobert Mustacchi
781*32002227SRobert Mustacchi if (dev_dn != DI_NODE_NIL) {
782*32002227SRobert Mustacchi if (!i2c_device_info_snap(hdl, dev_dn, infop)) {
783*32002227SRobert Mustacchi di_fini(root);
784*32002227SRobert Mustacchi i2c_port_fini(*portp);
785*32002227SRobert Mustacchi return (false);
786*32002227SRobert Mustacchi }
787*32002227SRobert Mustacchi }
788*32002227SRobert Mustacchi
789*32002227SRobert Mustacchi return (true);
790*32002227SRobert Mustacchi }
791