xref: /illumos-gate/usr/src/lib/libi2c/common/libi2c_ctrl.c (revision 32002227574cf0a435dc03de622191ca53724f0a)
1*32002227SRobert Mustacchi /*
2*32002227SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*32002227SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*32002227SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*32002227SRobert Mustacchi  * 1.0 of the CDDL.
6*32002227SRobert Mustacchi  *
7*32002227SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*32002227SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*32002227SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*32002227SRobert Mustacchi  */
11*32002227SRobert Mustacchi 
12*32002227SRobert Mustacchi /*
13*32002227SRobert Mustacchi  * Copyright 2025 Oxide Computer Company
14*32002227SRobert Mustacchi  */
15*32002227SRobert Mustacchi 
16*32002227SRobert Mustacchi /*
17*32002227SRobert Mustacchi  * 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