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 Controller related functions.
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_ctrl_discover_fini(i2c_ctrl_iter_t * iter)30*32002227SRobert Mustacchi i2c_ctrl_discover_fini(i2c_ctrl_iter_t *iter)
31*32002227SRobert Mustacchi {
32*32002227SRobert Mustacchi if (iter == NULL)
33*32002227SRobert Mustacchi return;
34*32002227SRobert Mustacchi
35*32002227SRobert Mustacchi di_fini(iter->ci_root);
36*32002227SRobert Mustacchi free(iter);
37*32002227SRobert Mustacchi }
38*32002227SRobert Mustacchi
39*32002227SRobert Mustacchi i2c_iter_t
i2c_ctrl_discover_step(i2c_ctrl_iter_t * iter,const i2c_ctrl_disc_t ** discp)40*32002227SRobert Mustacchi i2c_ctrl_discover_step(i2c_ctrl_iter_t *iter, const i2c_ctrl_disc_t **discp)
41*32002227SRobert Mustacchi {
42*32002227SRobert Mustacchi *discp = NULL;
43*32002227SRobert Mustacchi
44*32002227SRobert Mustacchi if (iter->ci_done) {
45*32002227SRobert Mustacchi return (I2C_ITER_DONE);
46*32002227SRobert Mustacchi }
47*32002227SRobert Mustacchi
48*32002227SRobert Mustacchi for (;;) {
49*32002227SRobert Mustacchi if (iter->ci_cur == DI_NODE_NIL) {
50*32002227SRobert Mustacchi iter->ci_cur = di_drv_first_node(I2C_NEX_DRV,
51*32002227SRobert Mustacchi iter->ci_root);
52*32002227SRobert Mustacchi } else {
53*32002227SRobert Mustacchi iter->ci_cur = di_drv_next_node(iter->ci_cur);
54*32002227SRobert Mustacchi }
55*32002227SRobert Mustacchi
56*32002227SRobert Mustacchi if (iter->ci_cur == DI_NODE_NIL) {
57*32002227SRobert Mustacchi iter->ci_done = true;
58*32002227SRobert Mustacchi return (I2C_ITER_DONE);
59*32002227SRobert Mustacchi }
60*32002227SRobert Mustacchi
61*32002227SRobert Mustacchi if (!i2c_node_is_type(iter->ci_cur, I2C_NODE_T_CTRL)) {
62*32002227SRobert Mustacchi continue;
63*32002227SRobert Mustacchi }
64*32002227SRobert Mustacchi
65*32002227SRobert Mustacchi iter->ci_disc.icd_devi = iter->ci_cur;
66*32002227SRobert Mustacchi iter->ci_disc.icd_minor = i2c_node_minor(iter->ci_cur);
67*32002227SRobert Mustacchi if (iter->ci_disc.icd_minor == DI_MINOR_NIL) {
68*32002227SRobert Mustacchi continue;
69*32002227SRobert Mustacchi }
70*32002227SRobert Mustacchi
71*32002227SRobert Mustacchi *discp = &iter->ci_disc;
72*32002227SRobert Mustacchi return (I2C_ITER_VALID);
73*32002227SRobert Mustacchi }
74*32002227SRobert Mustacchi
75*32002227SRobert Mustacchi return (I2C_ITER_DONE);
76*32002227SRobert Mustacchi }
77*32002227SRobert Mustacchi
78*32002227SRobert Mustacchi bool
i2c_ctrl_discover_init(i2c_hdl_t * hdl,i2c_ctrl_iter_t ** iterp)79*32002227SRobert Mustacchi i2c_ctrl_discover_init(i2c_hdl_t *hdl, i2c_ctrl_iter_t **iterp)
80*32002227SRobert Mustacchi {
81*32002227SRobert Mustacchi i2c_ctrl_iter_t *iter;
82*32002227SRobert Mustacchi
83*32002227SRobert Mustacchi if (iterp == NULL) {
84*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
85*32002227SRobert Mustacchi "invalid i2c_ctrl_iter_t output pointer: %p", iterp));
86*32002227SRobert Mustacchi }
87*32002227SRobert Mustacchi
88*32002227SRobert Mustacchi iter = calloc(1, sizeof (i2c_ctrl_iter_t));
89*32002227SRobert Mustacchi if (iter == NULL) {
90*32002227SRobert Mustacchi int e = errno;
91*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
92*32002227SRobert Mustacchi "memory for a new i2c_ctrl_iter_t"));
93*32002227SRobert Mustacchi }
94*32002227SRobert Mustacchi
95*32002227SRobert Mustacchi iter->ci_hdl = hdl;
96*32002227SRobert Mustacchi iter->ci_root = di_init("/", DINFOCPYALL);
97*32002227SRobert Mustacchi if (iter->ci_root == NULL) {
98*32002227SRobert Mustacchi int e = errno;
99*32002227SRobert Mustacchi i2c_ctrl_discover_fini(iter);
100*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
101*32002227SRobert Mustacchi "initialize devinfo snapshot: %s", strerrordesc_np(e)));
102*32002227SRobert Mustacchi }
103*32002227SRobert Mustacchi iter->ci_done = false;
104*32002227SRobert Mustacchi iter->ci_cur = DI_NODE_NIL;
105*32002227SRobert Mustacchi
106*32002227SRobert Mustacchi *iterp = iter;
107*32002227SRobert Mustacchi return (i2c_success(hdl));
108*32002227SRobert Mustacchi }
109*32002227SRobert Mustacchi
110*32002227SRobert Mustacchi bool
i2c_ctrl_discover(i2c_hdl_t * hdl,i2c_ctrl_disc_f func,void * arg)111*32002227SRobert Mustacchi i2c_ctrl_discover(i2c_hdl_t *hdl, i2c_ctrl_disc_f func, void *arg)
112*32002227SRobert Mustacchi {
113*32002227SRobert Mustacchi i2c_ctrl_iter_t *iter;
114*32002227SRobert Mustacchi const i2c_ctrl_disc_t *disc;
115*32002227SRobert Mustacchi i2c_iter_t ret;
116*32002227SRobert Mustacchi
117*32002227SRobert Mustacchi if (func == NULL) {
118*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
119*32002227SRobert Mustacchi "invalid i2c_ctrl_disc_f function pointer: %p", func));
120*32002227SRobert Mustacchi }
121*32002227SRobert Mustacchi
122*32002227SRobert Mustacchi if (!i2c_ctrl_discover_init(hdl, &iter)) {
123*32002227SRobert Mustacchi return (false);
124*32002227SRobert Mustacchi }
125*32002227SRobert Mustacchi
126*32002227SRobert Mustacchi while ((ret = i2c_ctrl_discover_step(iter, &disc)) == I2C_ITER_VALID) {
127*32002227SRobert Mustacchi if (!func(hdl, disc, arg))
128*32002227SRobert Mustacchi break;
129*32002227SRobert Mustacchi }
130*32002227SRobert Mustacchi
131*32002227SRobert Mustacchi i2c_ctrl_discover_fini(iter);
132*32002227SRobert Mustacchi if (ret == I2C_ITER_ERROR) {
133*32002227SRobert Mustacchi return (false);
134*32002227SRobert Mustacchi }
135*32002227SRobert Mustacchi
136*32002227SRobert Mustacchi return (i2c_success(hdl));
137*32002227SRobert Mustacchi }
138*32002227SRobert Mustacchi
139*32002227SRobert Mustacchi di_node_t
i2c_ctrl_disc_devi(const i2c_ctrl_disc_t * discp)140*32002227SRobert Mustacchi i2c_ctrl_disc_devi(const i2c_ctrl_disc_t *discp)
141*32002227SRobert Mustacchi {
142*32002227SRobert Mustacchi return (discp->icd_devi);
143*32002227SRobert Mustacchi }
144*32002227SRobert Mustacchi
145*32002227SRobert Mustacchi di_minor_t
i2c_ctrl_disc_minor(const i2c_ctrl_disc_t * discp)146*32002227SRobert Mustacchi i2c_ctrl_disc_minor(const i2c_ctrl_disc_t *discp)
147*32002227SRobert Mustacchi {
148*32002227SRobert Mustacchi return (discp->icd_minor);
149*32002227SRobert Mustacchi }
150*32002227SRobert Mustacchi
151*32002227SRobert Mustacchi void
i2c_ctrl_fini(i2c_ctrl_t * ctrl)152*32002227SRobert Mustacchi i2c_ctrl_fini(i2c_ctrl_t *ctrl)
153*32002227SRobert Mustacchi {
154*32002227SRobert Mustacchi if (ctrl == NULL) {
155*32002227SRobert Mustacchi return;
156*32002227SRobert Mustacchi }
157*32002227SRobert Mustacchi
158*32002227SRobert Mustacchi if (ctrl->ctrl_fd >= 0) {
159*32002227SRobert Mustacchi (void) close(ctrl->ctrl_fd);
160*32002227SRobert Mustacchi }
161*32002227SRobert Mustacchi
162*32002227SRobert Mustacchi di_devfs_path_free(ctrl->ctrl_minor);
163*32002227SRobert Mustacchi di_devfs_path_free(ctrl->ctrl_path);
164*32002227SRobert Mustacchi free(ctrl->ctrl_name);
165*32002227SRobert Mustacchi free(ctrl);
166*32002227SRobert Mustacchi }
167*32002227SRobert Mustacchi
168*32002227SRobert Mustacchi bool
i2c_ctrl_init(i2c_hdl_t * hdl,di_node_t di,i2c_ctrl_t ** ctrlp)169*32002227SRobert Mustacchi i2c_ctrl_init(i2c_hdl_t *hdl, di_node_t di, i2c_ctrl_t **ctrlp)
170*32002227SRobert Mustacchi {
171*32002227SRobert Mustacchi di_minor_t minor;
172*32002227SRobert Mustacchi i2c_ctrl_t *ctrl;
173*32002227SRobert Mustacchi ui2c_ctrl_nprops_t nprops;
174*32002227SRobert Mustacchi
175*32002227SRobert Mustacchi if (di == DI_NODE_NIL) {
176*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
177*32002227SRobert Mustacchi "invalid di_node_t: %p", di));
178*32002227SRobert Mustacchi }
179*32002227SRobert Mustacchi
180*32002227SRobert Mustacchi if (ctrlp == NULL) {
181*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
182*32002227SRobert Mustacchi "invalid i2c_ctrl_t output pointer: %p", ctrlp));
183*32002227SRobert Mustacchi }
184*32002227SRobert Mustacchi
185*32002227SRobert Mustacchi if (!i2c_node_is_type(di, I2C_NODE_T_CTRL)) {
186*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVI, 0, "devi %s@%s isn't "
187*32002227SRobert Mustacchi "an i2c controller", di_node_name(di), di_bus_addr(di)));
188*32002227SRobert Mustacchi }
189*32002227SRobert Mustacchi
190*32002227SRobert Mustacchi /*
191*32002227SRobert Mustacchi * See if we can find a minor node that corresponds to a controller
192*32002227SRobert Mustacchi * nexus.
193*32002227SRobert Mustacchi */
194*32002227SRobert Mustacchi minor = i2c_node_minor(di);
195*32002227SRobert Mustacchi if (minor == DI_MINOR_NIL) {
196*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_DEVI, 0, "devi %s@%s is "
197*32002227SRobert Mustacchi "not an i2c controller: failed to find controller minor",
198*32002227SRobert Mustacchi di_node_name(di), di_bus_addr(di)));
199*32002227SRobert Mustacchi }
200*32002227SRobert Mustacchi
201*32002227SRobert Mustacchi ctrl = calloc(1, sizeof (i2c_ctrl_t));
202*32002227SRobert Mustacchi if (ctrl == NULL) {
203*32002227SRobert Mustacchi int e = errno;
204*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
205*32002227SRobert Mustacchi "memory for a new i2c_ctrl_t"));
206*32002227SRobert Mustacchi }
207*32002227SRobert Mustacchi
208*32002227SRobert Mustacchi ctrl->ctrl_fd = -1;
209*32002227SRobert Mustacchi ctrl->ctrl_hdl = hdl;
210*32002227SRobert Mustacchi ctrl->ctrl_inst = di_instance(di);
211*32002227SRobert Mustacchi ctrl->ctrl_name = strdup(di_bus_addr(di));
212*32002227SRobert Mustacchi if (ctrl->ctrl_name == NULL) {
213*32002227SRobert Mustacchi int e = errno;
214*32002227SRobert Mustacchi i2c_ctrl_fini(ctrl);
215*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to duplicate "
216*32002227SRobert Mustacchi "controller bus address"));
217*32002227SRobert Mustacchi }
218*32002227SRobert Mustacchi
219*32002227SRobert Mustacchi ctrl->ctrl_path = di_devfs_path(di);
220*32002227SRobert Mustacchi if (ctrl->ctrl_path == NULL) {
221*32002227SRobert Mustacchi int e = errno;
222*32002227SRobert Mustacchi i2c_ctrl_fini(ctrl);
223*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
224*32002227SRobert Mustacchi "obtain controller's devfs path: %s", strerrordesc_np(e)));
225*32002227SRobert Mustacchi }
226*32002227SRobert Mustacchi
227*32002227SRobert Mustacchi ctrl->ctrl_minor = di_devfs_minor_path(minor);
228*32002227SRobert Mustacchi if (ctrl->ctrl_minor == NULL) {
229*32002227SRobert Mustacchi int e = errno;
230*32002227SRobert Mustacchi i2c_ctrl_fini(ctrl);
231*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
232*32002227SRobert Mustacchi "obtain controller's minor path: %s", strerrordesc_np(e)));
233*32002227SRobert Mustacchi }
234*32002227SRobert Mustacchi
235*32002227SRobert Mustacchi ctrl->ctrl_fd = openat(hdl->ih_devfd, ctrl->ctrl_minor + 1, O_RDWR);
236*32002227SRobert Mustacchi if (ctrl->ctrl_fd < 0) {
237*32002227SRobert Mustacchi int e = errno;
238*32002227SRobert Mustacchi (void) i2c_error(hdl, I2C_ERR_OPEN_DEV, e, "failed to open "
239*32002227SRobert Mustacchi "device path '/devices%s: %s", ctrl->ctrl_minor,
240*32002227SRobert Mustacchi strerrordesc_np(e));
241*32002227SRobert Mustacchi i2c_ctrl_fini(ctrl);
242*32002227SRobert Mustacchi return (false);
243*32002227SRobert Mustacchi }
244*32002227SRobert Mustacchi
245*32002227SRobert Mustacchi if (ioctl(ctrl->ctrl_fd, UI2C_IOCTL_CTRL_NPROPS, &nprops) != 0) {
246*32002227SRobert Mustacchi int e = errno;
247*32002227SRobert Mustacchi i2c_ctrl_fini(ctrl);
248*32002227SRobert Mustacchi return (i2c_ioctl_syserror(hdl, e, "controller nprops "
249*32002227SRobert Mustacchi "request"));
250*32002227SRobert Mustacchi }
251*32002227SRobert Mustacchi ctrl->ctrl_nstd = nprops.ucp_nstd;
252*32002227SRobert Mustacchi ctrl->ctrl_npriv = nprops.ucp_npriv;
253*32002227SRobert Mustacchi
254*32002227SRobert Mustacchi *ctrlp = ctrl;
255*32002227SRobert Mustacchi return (i2c_success(hdl));
256*32002227SRobert Mustacchi }
257*32002227SRobert Mustacchi
258*32002227SRobert Mustacchi bool
i2c_ctrl_init_by_path(i2c_hdl_t * hdl,const char * name,i2c_ctrl_t ** ctrlp)259*32002227SRobert Mustacchi i2c_ctrl_init_by_path(i2c_hdl_t *hdl, const char *name, i2c_ctrl_t **ctrlp)
260*32002227SRobert Mustacchi {
261*32002227SRobert Mustacchi i2c_node_type_t type;
262*32002227SRobert Mustacchi di_node_t dn, root;
263*32002227SRobert Mustacchi
264*32002227SRobert Mustacchi if (name == NULL) {
265*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
266*32002227SRobert Mustacchi "invalid i2c controller name: %p", name));
267*32002227SRobert Mustacchi }
268*32002227SRobert Mustacchi
269*32002227SRobert Mustacchi if (ctrlp == NULL) {
270*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
271*32002227SRobert Mustacchi "invalid i2c_ctrl_t output pointer: %p", ctrlp));
272*32002227SRobert Mustacchi }
273*32002227SRobert Mustacchi
274*32002227SRobert Mustacchi root = di_init("/", DINFOCPYALL);
275*32002227SRobert Mustacchi if (root == DI_NODE_NIL) {
276*32002227SRobert Mustacchi int e = errno;
277*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_LIBDEVINFO, e, "failed to "
278*32002227SRobert Mustacchi "initialize devinfo snapshot: %s", strerrordesc_np(e)));
279*32002227SRobert Mustacchi }
280*32002227SRobert Mustacchi
281*32002227SRobert Mustacchi if (!i2c_path_parse(hdl, name, root, &dn, &type,
282*32002227SRobert Mustacchi I2C_ERR_BAD_CONTROLLER)) {
283*32002227SRobert Mustacchi di_fini(root);
284*32002227SRobert Mustacchi return (false);
285*32002227SRobert Mustacchi }
286*32002227SRobert Mustacchi
287*32002227SRobert Mustacchi if (type != I2C_NODE_T_CTRL) {
288*32002227SRobert Mustacchi di_fini(root);
289*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_CONTROLLER, 0, "parsed I2C "
290*32002227SRobert Mustacchi "path %s did not end at a controller", name));
291*32002227SRobert Mustacchi }
292*32002227SRobert Mustacchi
293*32002227SRobert Mustacchi bool ret = i2c_ctrl_init(hdl, dn, ctrlp);
294*32002227SRobert Mustacchi di_fini(root);
295*32002227SRobert Mustacchi return (ret);
296*32002227SRobert Mustacchi }
297*32002227SRobert Mustacchi
298*32002227SRobert Mustacchi const char *
i2c_ctrl_name(i2c_ctrl_t * ctrl)299*32002227SRobert Mustacchi i2c_ctrl_name(i2c_ctrl_t *ctrl)
300*32002227SRobert Mustacchi {
301*32002227SRobert Mustacchi return (ctrl->ctrl_name);
302*32002227SRobert Mustacchi }
303*32002227SRobert Mustacchi
304*32002227SRobert Mustacchi int32_t
i2c_ctrl_instance(i2c_ctrl_t * ctrl)305*32002227SRobert Mustacchi i2c_ctrl_instance(i2c_ctrl_t *ctrl)
306*32002227SRobert Mustacchi {
307*32002227SRobert Mustacchi return (ctrl->ctrl_inst);
308*32002227SRobert Mustacchi }
309*32002227SRobert Mustacchi
310*32002227SRobert Mustacchi const char *
i2c_ctrl_path(i2c_ctrl_t * ctrl)311*32002227SRobert Mustacchi i2c_ctrl_path(i2c_ctrl_t *ctrl)
312*32002227SRobert Mustacchi {
313*32002227SRobert Mustacchi return (ctrl->ctrl_path);
314*32002227SRobert Mustacchi }
315*32002227SRobert Mustacchi
316*32002227SRobert Mustacchi uint32_t
i2c_ctrl_nprops(i2c_ctrl_t * ctrl)317*32002227SRobert Mustacchi i2c_ctrl_nprops(i2c_ctrl_t *ctrl)
318*32002227SRobert Mustacchi {
319*32002227SRobert Mustacchi /*
320*32002227SRobert Mustacchi * Currently we only have standard properties. If we have
321*32002227SRobert Mustacchi * controller-specific properties in the future then those should be
322*32002227SRobert Mustacchi * added to this.
323*32002227SRobert Mustacchi */
324*32002227SRobert Mustacchi return (ctrl->ctrl_nstd);
325*32002227SRobert Mustacchi }
326*32002227SRobert Mustacchi
327*32002227SRobert Mustacchi const char *
i2c_prop_info_name(i2c_prop_info_t * info)328*32002227SRobert Mustacchi i2c_prop_info_name(i2c_prop_info_t *info)
329*32002227SRobert Mustacchi {
330*32002227SRobert Mustacchi return (info->pinfo_info.upi_name);
331*32002227SRobert Mustacchi }
332*32002227SRobert Mustacchi
333*32002227SRobert Mustacchi i2c_prop_t
i2c_prop_info_id(i2c_prop_info_t * info)334*32002227SRobert Mustacchi i2c_prop_info_id(i2c_prop_info_t *info)
335*32002227SRobert Mustacchi {
336*32002227SRobert Mustacchi return (info->pinfo_info.upi_prop);
337*32002227SRobert Mustacchi }
338*32002227SRobert Mustacchi
339*32002227SRobert Mustacchi i2c_prop_type_t
i2c_prop_info_type(i2c_prop_info_t * info)340*32002227SRobert Mustacchi i2c_prop_info_type(i2c_prop_info_t *info)
341*32002227SRobert Mustacchi {
342*32002227SRobert Mustacchi return (info->pinfo_info.upi_type);
343*32002227SRobert Mustacchi }
344*32002227SRobert Mustacchi
345*32002227SRobert Mustacchi bool
i2c_prop_info_sup(i2c_prop_info_t * info)346*32002227SRobert Mustacchi i2c_prop_info_sup(i2c_prop_info_t *info)
347*32002227SRobert Mustacchi {
348*32002227SRobert Mustacchi return (info->pinfo_sup);
349*32002227SRobert Mustacchi }
350*32002227SRobert Mustacchi
351*32002227SRobert Mustacchi i2c_prop_perm_t
i2c_prop_info_perm(i2c_prop_info_t * info)352*32002227SRobert Mustacchi i2c_prop_info_perm(i2c_prop_info_t *info)
353*32002227SRobert Mustacchi {
354*32002227SRobert Mustacchi return (info->pinfo_info.upi_perm);
355*32002227SRobert Mustacchi }
356*32002227SRobert Mustacchi
357*32002227SRobert Mustacchi bool
i2c_prop_info_def_u32(i2c_prop_info_t * info,uint32_t * defp)358*32002227SRobert Mustacchi i2c_prop_info_def_u32(i2c_prop_info_t *info, uint32_t *defp)
359*32002227SRobert Mustacchi {
360*32002227SRobert Mustacchi i2c_hdl_t *hdl = info->pinfo_hdl;
361*32002227SRobert Mustacchi
362*32002227SRobert Mustacchi if (defp == NULL) {
363*32002227SRobert Mustacchi
364*32002227SRobert Mustacchi }
365*32002227SRobert Mustacchi
366*32002227SRobert Mustacchi if (!info->pinfo_sup) {
367*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_PROP_UNSUP, 0, "default value "
368*32002227SRobert Mustacchi "is unavailable because property %s is not supported by "
369*32002227SRobert Mustacchi "the controller", info->pinfo_info.upi_name));
370*32002227SRobert Mustacchi }
371*32002227SRobert Mustacchi
372*32002227SRobert Mustacchi switch (info->pinfo_info.upi_type) {
373*32002227SRobert Mustacchi case I2C_PROP_TYPE_U32:
374*32002227SRobert Mustacchi case I2C_PROP_TYPE_BIT32:
375*32002227SRobert Mustacchi if (info->pinfo_info.upi_def_len != sizeof (uint32_t)) {
376*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_PROP_TYPE_MISMATCH, 0,
377*32002227SRobert Mustacchi "property %s does not have a default value",
378*32002227SRobert Mustacchi info->pinfo_info.upi_name));
379*32002227SRobert Mustacchi }
380*32002227SRobert Mustacchi (void) memcpy(defp, info->pinfo_info.upi_def,
381*32002227SRobert Mustacchi sizeof (uint32_t));
382*32002227SRobert Mustacchi break;
383*32002227SRobert Mustacchi default:
384*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_PROP_TYPE_MISMATCH, 0,
385*32002227SRobert Mustacchi "property %s default value does not have a 32-bit "
386*32002227SRobert Mustacchi "integer type (found type 0x%x)", info->pinfo_info.upi_name,
387*32002227SRobert Mustacchi info->pinfo_info.upi_type));
388*32002227SRobert Mustacchi break;
389*32002227SRobert Mustacchi }
390*32002227SRobert Mustacchi
391*32002227SRobert Mustacchi return (i2c_success(hdl));
392*32002227SRobert Mustacchi }
393*32002227SRobert Mustacchi
394*32002227SRobert Mustacchi const i2c_prop_range_t *
i2c_prop_info_pos(i2c_prop_info_t * info)395*32002227SRobert Mustacchi i2c_prop_info_pos(i2c_prop_info_t *info)
396*32002227SRobert Mustacchi {
397*32002227SRobert Mustacchi if (!info->pinfo_sup || info->pinfo_info.upi_pos_len <
398*32002227SRobert Mustacchi sizeof (i2c_prop_range_t)) {
399*32002227SRobert Mustacchi return (NULL);
400*32002227SRobert Mustacchi }
401*32002227SRobert Mustacchi
402*32002227SRobert Mustacchi return ((i2c_prop_range_t *)info->pinfo_info.upi_pos);
403*32002227SRobert Mustacchi }
404*32002227SRobert Mustacchi
405*32002227SRobert Mustacchi void
i2c_prop_info_free(i2c_prop_info_t * info)406*32002227SRobert Mustacchi i2c_prop_info_free(i2c_prop_info_t *info)
407*32002227SRobert Mustacchi {
408*32002227SRobert Mustacchi free(info);
409*32002227SRobert Mustacchi }
410*32002227SRobert Mustacchi
411*32002227SRobert Mustacchi bool
i2c_prop_info(i2c_ctrl_t * ctrl,i2c_prop_t prop,i2c_prop_info_t ** infop)412*32002227SRobert Mustacchi i2c_prop_info(i2c_ctrl_t *ctrl, i2c_prop_t prop, i2c_prop_info_t **infop)
413*32002227SRobert Mustacchi {
414*32002227SRobert Mustacchi i2c_hdl_t *hdl = ctrl->ctrl_hdl;
415*32002227SRobert Mustacchi i2c_prop_info_t *info;
416*32002227SRobert Mustacchi
417*32002227SRobert Mustacchi if (infop == NULL) {
418*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
419*32002227SRobert Mustacchi "invalid i2c_prop_info_t output pointer: %p", infop));
420*32002227SRobert Mustacchi }
421*32002227SRobert Mustacchi
422*32002227SRobert Mustacchi info = calloc(1, sizeof (i2c_prop_info_t));
423*32002227SRobert Mustacchi if (info == NULL) {
424*32002227SRobert Mustacchi int e = errno;
425*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_NO_MEM, e, "failed to allocate "
426*32002227SRobert Mustacchi "memory for a new i2c_prop_info_t"));
427*32002227SRobert Mustacchi }
428*32002227SRobert Mustacchi
429*32002227SRobert Mustacchi info->pinfo_info.upi_prop = prop;
430*32002227SRobert Mustacchi if (ioctl(ctrl->ctrl_fd, UI2C_IOCTL_CTRL_PROP_INFO,
431*32002227SRobert Mustacchi &info->pinfo_info) != 0) {
432*32002227SRobert Mustacchi int e = errno;
433*32002227SRobert Mustacchi return (i2c_ioctl_syserror(hdl, e, "property info request"));
434*32002227SRobert Mustacchi }
435*32002227SRobert Mustacchi
436*32002227SRobert Mustacchi i2c_error_t *err = &info->pinfo_info.upi_error;
437*32002227SRobert Mustacchi if (err->i2c_error != I2C_CORE_E_OK &&
438*32002227SRobert Mustacchi err->i2c_error != I2C_PROP_E_UNSUP) {
439*32002227SRobert Mustacchi free(info);
440*32002227SRobert Mustacchi return (i2c_ioctl_error(hdl, err, "property info request"));
441*32002227SRobert Mustacchi }
442*32002227SRobert Mustacchi
443*32002227SRobert Mustacchi info->pinfo_hdl = hdl;
444*32002227SRobert Mustacchi info->pinfo_sup = err->i2c_error == I2C_CORE_E_OK;
445*32002227SRobert Mustacchi *infop = info;
446*32002227SRobert Mustacchi return (i2c_success(hdl));
447*32002227SRobert Mustacchi }
448*32002227SRobert Mustacchi
449*32002227SRobert Mustacchi /*
450*32002227SRobert Mustacchi * Find the property that maps to name the max power way. Basically iterate over
451*32002227SRobert Mustacchi * all known properties and see if the name matches.
452*32002227SRobert Mustacchi */
453*32002227SRobert Mustacchi bool
i2c_prop_info_by_name(i2c_ctrl_t * ctrl,const char * name,i2c_prop_info_t ** infop)454*32002227SRobert Mustacchi i2c_prop_info_by_name(i2c_ctrl_t *ctrl, const char *name,
455*32002227SRobert Mustacchi i2c_prop_info_t **infop)
456*32002227SRobert Mustacchi {
457*32002227SRobert Mustacchi i2c_hdl_t *hdl = ctrl->ctrl_hdl;
458*32002227SRobert Mustacchi i2c_prop_info_t *info;
459*32002227SRobert Mustacchi
460*32002227SRobert Mustacchi if (name == NULL) {
461*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
462*32002227SRobert Mustacchi "invalid property name pointer: %p", name));
463*32002227SRobert Mustacchi }
464*32002227SRobert Mustacchi
465*32002227SRobert Mustacchi if (infop == NULL) {
466*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
467*32002227SRobert Mustacchi "invalid i2c_prop_info_t output pointer: %p", infop));
468*32002227SRobert Mustacchi }
469*32002227SRobert Mustacchi
470*32002227SRobert Mustacchi for (uint32_t i = 0; i < ctrl->ctrl_nstd; i++) {
471*32002227SRobert Mustacchi if (!i2c_prop_info(ctrl, i, &info)) {
472*32002227SRobert Mustacchi return (false);
473*32002227SRobert Mustacchi }
474*32002227SRobert Mustacchi
475*32002227SRobert Mustacchi if (strcmp(name, i2c_prop_info_name(info)) == 0) {
476*32002227SRobert Mustacchi *infop = info;
477*32002227SRobert Mustacchi return (i2c_success(hdl));
478*32002227SRobert Mustacchi }
479*32002227SRobert Mustacchi
480*32002227SRobert Mustacchi i2c_prop_info_free(info);
481*32002227SRobert Mustacchi }
482*32002227SRobert Mustacchi
483*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PROP, 0, "unkonwn property: %s",
484*32002227SRobert Mustacchi name));
485*32002227SRobert Mustacchi }
486*32002227SRobert Mustacchi
487*32002227SRobert Mustacchi bool
i2c_prop_get(i2c_ctrl_t * ctrl,i2c_prop_t id,void * buf,size_t * lenp)488*32002227SRobert Mustacchi i2c_prop_get(i2c_ctrl_t *ctrl, i2c_prop_t id, void *buf, size_t *lenp)
489*32002227SRobert Mustacchi {
490*32002227SRobert Mustacchi i2c_hdl_t *hdl = ctrl->ctrl_hdl;
491*32002227SRobert Mustacchi ui2c_prop_t prop;
492*32002227SRobert Mustacchi
493*32002227SRobert Mustacchi if (buf == NULL) {
494*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
495*32002227SRobert Mustacchi "invalid property data buffer pointer: %p", buf));
496*32002227SRobert Mustacchi }
497*32002227SRobert Mustacchi
498*32002227SRobert Mustacchi if (lenp == NULL) {
499*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
500*32002227SRobert Mustacchi "invalid property size pointer: %p", buf));
501*32002227SRobert Mustacchi }
502*32002227SRobert Mustacchi
503*32002227SRobert Mustacchi (void) memset(&prop, 0, sizeof (ui2c_prop_t));
504*32002227SRobert Mustacchi prop.up_prop = id;
505*32002227SRobert Mustacchi
506*32002227SRobert Mustacchi if (ioctl(ctrl->ctrl_fd, UI2C_IOCTL_CTRL_PROP_GET, &prop) != 0) {
507*32002227SRobert Mustacchi int e = errno;
508*32002227SRobert Mustacchi return (i2c_ioctl_syserror(hdl, e, "property get request"));
509*32002227SRobert Mustacchi }
510*32002227SRobert Mustacchi
511*32002227SRobert Mustacchi if (prop.up_error.i2c_error != I2C_CORE_E_OK) {
512*32002227SRobert Mustacchi return (i2c_ioctl_error(hdl, &prop.up_error,
513*32002227SRobert Mustacchi "property get request"));
514*32002227SRobert Mustacchi }
515*32002227SRobert Mustacchi
516*32002227SRobert Mustacchi size_t orig = *lenp;
517*32002227SRobert Mustacchi *lenp = prop.up_size;
518*32002227SRobert Mustacchi if (orig < prop.up_size) {
519*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_PROP_BUF_TOO_SMALL, 0,
520*32002227SRobert Mustacchi "property requires %u bytes to hold data, but only passed "
521*32002227SRobert Mustacchi "a buffer of %zu bytes", prop.up_size, orig));
522*32002227SRobert Mustacchi }
523*32002227SRobert Mustacchi
524*32002227SRobert Mustacchi (void) memcpy(buf, prop.up_value, prop.up_size);
525*32002227SRobert Mustacchi return (i2c_success(hdl));
526*32002227SRobert Mustacchi }
527*32002227SRobert Mustacchi
528*32002227SRobert Mustacchi bool
i2c_prop_set(i2c_ctrl_t * ctrl,i2c_prop_t id,const void * buf,size_t len)529*32002227SRobert Mustacchi i2c_prop_set(i2c_ctrl_t *ctrl, i2c_prop_t id, const void *buf, size_t len)
530*32002227SRobert Mustacchi {
531*32002227SRobert Mustacchi i2c_hdl_t *hdl = ctrl->ctrl_hdl;
532*32002227SRobert Mustacchi ui2c_prop_t prop;
533*32002227SRobert Mustacchi
534*32002227SRobert Mustacchi if (buf == NULL) {
535*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_BAD_PTR, 0, "encountered "
536*32002227SRobert Mustacchi "invalid property data buffer pointer: %p", buf));
537*32002227SRobert Mustacchi }
538*32002227SRobert Mustacchi
539*32002227SRobert Mustacchi if (len == 0) {
540*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_PROP_BUF_TOO_SMALL, 0,
541*32002227SRobert Mustacchi "property buffer length must be more than 0"));
542*32002227SRobert Mustacchi }
543*32002227SRobert Mustacchi
544*32002227SRobert Mustacchi if (len > I2C_PROP_SIZE_MAX) {
545*32002227SRobert Mustacchi return (i2c_error(hdl, I2C_ERR_PROP_BUF_TOO_BIG, 0,
546*32002227SRobert Mustacchi "property buffer length must be less than or equal to %u",
547*32002227SRobert Mustacchi I2C_PROP_SIZE_MAX));
548*32002227SRobert Mustacchi }
549*32002227SRobert Mustacchi
550*32002227SRobert Mustacchi (void) memset(&prop, 0, sizeof (ui2c_prop_t));
551*32002227SRobert Mustacchi prop.up_prop = id;
552*32002227SRobert Mustacchi prop.up_size = len;
553*32002227SRobert Mustacchi (void) memcpy(&prop.up_value, buf, len);
554*32002227SRobert Mustacchi
555*32002227SRobert Mustacchi if (ioctl(ctrl->ctrl_fd, UI2C_IOCTL_CTRL_PROP_SET, &prop) != 0) {
556*32002227SRobert Mustacchi int e = errno;
557*32002227SRobert Mustacchi return (i2c_ioctl_syserror(hdl, e, "property set request"));
558*32002227SRobert Mustacchi }
559*32002227SRobert Mustacchi
560*32002227SRobert Mustacchi if (prop.up_error.i2c_error != I2C_CORE_E_OK) {
561*32002227SRobert Mustacchi return (i2c_ioctl_error(hdl, &prop.up_error,
562*32002227SRobert Mustacchi "property set request"));
563*32002227SRobert Mustacchi }
564*32002227SRobert Mustacchi
565*32002227SRobert Mustacchi return (i2c_success(hdl));
566*32002227SRobert Mustacchi }
567