1*fd71220bSRobert Mustacchi /*
2*fd71220bSRobert Mustacchi * This file and its contents are supplied under the terms of the
3*fd71220bSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4*fd71220bSRobert Mustacchi * You may only use this file in accordance with the terms of version
5*fd71220bSRobert Mustacchi * 1.0 of the CDDL.
6*fd71220bSRobert Mustacchi *
7*fd71220bSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8*fd71220bSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
9*fd71220bSRobert Mustacchi * http://www.illumos.org/license/CDDL.
10*fd71220bSRobert Mustacchi */
11*fd71220bSRobert Mustacchi
12*fd71220bSRobert Mustacchi /*
13*fd71220bSRobert Mustacchi * Copyright 2022 Oxide Computer Company
14*fd71220bSRobert Mustacchi */
15*fd71220bSRobert Mustacchi
16*fd71220bSRobert Mustacchi /*
17*fd71220bSRobert Mustacchi * An evolving, but private, interface to the kernel xPIO (GPIO and DPIO)
18*fd71220bSRobert Mustacchi * subsystem.
19*fd71220bSRobert Mustacchi */
20*fd71220bSRobert Mustacchi
21*fd71220bSRobert Mustacchi #include <stddef.h>
22*fd71220bSRobert Mustacchi #include <stdlib.h>
23*fd71220bSRobert Mustacchi #include <stdio.h>
24*fd71220bSRobert Mustacchi #include <stdarg.h>
25*fd71220bSRobert Mustacchi #include <libdevinfo.h>
26*fd71220bSRobert Mustacchi #include <unistd.h>
27*fd71220bSRobert Mustacchi #include <string.h>
28*fd71220bSRobert Mustacchi #include <sys/types.h>
29*fd71220bSRobert Mustacchi #include <sys/stat.h>
30*fd71220bSRobert Mustacchi #include <fcntl.h>
31*fd71220bSRobert Mustacchi #include <sys/debug.h>
32*fd71220bSRobert Mustacchi
33*fd71220bSRobert Mustacchi #include "libxpio_impl.h"
34*fd71220bSRobert Mustacchi
35*fd71220bSRobert Mustacchi xpio_err_t
xpio_err(xpio_t * xpio)36*fd71220bSRobert Mustacchi xpio_err(xpio_t *xpio)
37*fd71220bSRobert Mustacchi {
38*fd71220bSRobert Mustacchi return (xpio->xp_err);
39*fd71220bSRobert Mustacchi }
40*fd71220bSRobert Mustacchi
41*fd71220bSRobert Mustacchi xpio_update_err_t
xpio_update_err(xpio_gpio_update_t * update)42*fd71220bSRobert Mustacchi xpio_update_err(xpio_gpio_update_t *update)
43*fd71220bSRobert Mustacchi {
44*fd71220bSRobert Mustacchi return (update->xgo_err);
45*fd71220bSRobert Mustacchi }
46*fd71220bSRobert Mustacchi
47*fd71220bSRobert Mustacchi int32_t
xpio_syserr(xpio_t * xpio)48*fd71220bSRobert Mustacchi xpio_syserr(xpio_t *xpio)
49*fd71220bSRobert Mustacchi {
50*fd71220bSRobert Mustacchi return (xpio->xp_syserr);
51*fd71220bSRobert Mustacchi }
52*fd71220bSRobert Mustacchi
53*fd71220bSRobert Mustacchi int32_t
xpio_update_syserr(xpio_gpio_update_t * update)54*fd71220bSRobert Mustacchi xpio_update_syserr(xpio_gpio_update_t *update)
55*fd71220bSRobert Mustacchi {
56*fd71220bSRobert Mustacchi return (update->xgo_syserr);
57*fd71220bSRobert Mustacchi }
58*fd71220bSRobert Mustacchi
59*fd71220bSRobert Mustacchi const char *
xpio_errmsg(xpio_t * xpio)60*fd71220bSRobert Mustacchi xpio_errmsg(xpio_t *xpio)
61*fd71220bSRobert Mustacchi {
62*fd71220bSRobert Mustacchi return (xpio->xp_errmsg);
63*fd71220bSRobert Mustacchi }
64*fd71220bSRobert Mustacchi
65*fd71220bSRobert Mustacchi const char *
xpio_update_errmsg(xpio_gpio_update_t * update)66*fd71220bSRobert Mustacchi xpio_update_errmsg(xpio_gpio_update_t *update)
67*fd71220bSRobert Mustacchi {
68*fd71220bSRobert Mustacchi return (update->xgo_errmsg);
69*fd71220bSRobert Mustacchi }
70*fd71220bSRobert Mustacchi
71*fd71220bSRobert Mustacchi const char *
xpio_err2str(xpio_t * xpio,xpio_err_t err)72*fd71220bSRobert Mustacchi xpio_err2str(xpio_t *xpio, xpio_err_t err)
73*fd71220bSRobert Mustacchi {
74*fd71220bSRobert Mustacchi switch (err) {
75*fd71220bSRobert Mustacchi case XPIO_ERR_OK:
76*fd71220bSRobert Mustacchi return ("XPIO_ERR_OK");
77*fd71220bSRobert Mustacchi case XPIO_ERR_NO_MEM:
78*fd71220bSRobert Mustacchi return ("XPIO_ERR_NO_MEM");
79*fd71220bSRobert Mustacchi case XPIO_ERR_LIBDEVINFO:
80*fd71220bSRobert Mustacchi return ("XPIO_ERR_LIBDEVINFO");
81*fd71220bSRobert Mustacchi case XPIO_ERR_INTERNAL:
82*fd71220bSRobert Mustacchi return ("XPIO_ERR_INTERNAL");
83*fd71220bSRobert Mustacchi case XPIO_ERR_BAD_PTR:
84*fd71220bSRobert Mustacchi return ("XPIO_ERR_BAD_PTR");
85*fd71220bSRobert Mustacchi case XPIO_ERR_WRONG_MINOR_TYPE:
86*fd71220bSRobert Mustacchi return ("XPIO_ERR_WRONG_MINOR_TYPE");
87*fd71220bSRobert Mustacchi case XPIO_ERR_OPEN_DEV:
88*fd71220bSRobert Mustacchi return ("XPIO_ERR_OPEN_DEV");
89*fd71220bSRobert Mustacchi case XPIO_ERR_KGPIO:
90*fd71220bSRobert Mustacchi return ("XPIO_ERR_KGPIO");
91*fd71220bSRobert Mustacchi case XPIO_ERR_BAD_CTRL_NAME:
92*fd71220bSRobert Mustacchi return ("XPIO_ERR_BAD_CTRL_NAME");
93*fd71220bSRobert Mustacchi case XPIO_ERR_BAD_GPIO_ID:
94*fd71220bSRobert Mustacchi return ("XPIO_ERR_BAD_GPIO_ID");
95*fd71220bSRobert Mustacchi case XPIO_ERR_BAD_UPDATE:
96*fd71220bSRobert Mustacchi return ("XPIO_ERR_BAD_UPDATE");
97*fd71220bSRobert Mustacchi case XPIO_ERR_BAD_DPIO_FEAT:
98*fd71220bSRobert Mustacchi return ("XPIO_ERR_BAD_DPIO_FEAT");
99*fd71220bSRobert Mustacchi case XPIO_ERR_BAD_DPIO_NAME:
100*fd71220bSRobert Mustacchi return ("XPIO_ERR_BAD_DPIO_NAME");
101*fd71220bSRobert Mustacchi case XPIO_ERR_BAD_GPIO_NAME:
102*fd71220bSRobert Mustacchi return ("XPIO_ERR_BAD_GPIO_NAME");
103*fd71220bSRobert Mustacchi case XPIO_ERR_NO_LOOKUP_MATCH:
104*fd71220bSRobert Mustacchi return ("XPIO_ERR_NO_LOOKUP_MATCH");
105*fd71220bSRobert Mustacchi default:
106*fd71220bSRobert Mustacchi return ("unknown error");
107*fd71220bSRobert Mustacchi }
108*fd71220bSRobert Mustacchi
109*fd71220bSRobert Mustacchi }
110*fd71220bSRobert Mustacchi
111*fd71220bSRobert Mustacchi const char *
xpio_update_err2str(xpio_gpio_update_t * update,xpio_update_err_t err)112*fd71220bSRobert Mustacchi xpio_update_err2str(xpio_gpio_update_t *update, xpio_update_err_t err)
113*fd71220bSRobert Mustacchi {
114*fd71220bSRobert Mustacchi switch (err) {
115*fd71220bSRobert Mustacchi case XPIO_UPDATE_ERR_OK:
116*fd71220bSRobert Mustacchi return ("XPIO_UPDATE_ERR_OK");
117*fd71220bSRobert Mustacchi case XPIO_UPDATE_ERR_RO:
118*fd71220bSRobert Mustacchi return ("XPIO_UPDATE_ERR_RO");
119*fd71220bSRobert Mustacchi case XPIO_UPDATE_ERR_UNKNOWN_ATTR:
120*fd71220bSRobert Mustacchi return ("XPIO_UPDATE_ERR_UNKNOWN_ATTR");
121*fd71220bSRobert Mustacchi case XPIO_UPDATE_ERR_BAD_TYPE:
122*fd71220bSRobert Mustacchi return ("XPIO_UPDATE_ERR_BAD_TYPE");
123*fd71220bSRobert Mustacchi case XPIO_UPDATE_ERR_UNKNOWN_VAL:
124*fd71220bSRobert Mustacchi return ("XPIO_UPDATE_ERR_UNKNOWN_VAL");
125*fd71220bSRobert Mustacchi case XPIO_UPDATE_ERR_CANT_APPLY_VAL:
126*fd71220bSRobert Mustacchi return ("XPIO_UPDATE_ERR_CANT_APPLY_VAL");
127*fd71220bSRobert Mustacchi case XPIO_UPDATE_ERR_NO_MEM:
128*fd71220bSRobert Mustacchi return ("XPIO_UPDATE_ERR_NO_MEM");
129*fd71220bSRobert Mustacchi case XPIO_UPDATE_ERR_INTERNAL:
130*fd71220bSRobert Mustacchi return ("XPIO_UPDATE_ERR_INTERNAL");
131*fd71220bSRobert Mustacchi default:
132*fd71220bSRobert Mustacchi return ("unknown error");
133*fd71220bSRobert Mustacchi }
134*fd71220bSRobert Mustacchi }
135*fd71220bSRobert Mustacchi
136*fd71220bSRobert Mustacchi bool
xpio_error(xpio_t * xpio,xpio_err_t err,int32_t sys,const char * fmt,...)137*fd71220bSRobert Mustacchi xpio_error(xpio_t *xpio, xpio_err_t err, int32_t sys, const char *fmt, ...)
138*fd71220bSRobert Mustacchi {
139*fd71220bSRobert Mustacchi va_list ap;
140*fd71220bSRobert Mustacchi
141*fd71220bSRobert Mustacchi xpio->xp_err = err;
142*fd71220bSRobert Mustacchi xpio->xp_syserr = sys;
143*fd71220bSRobert Mustacchi va_start(ap, fmt);
144*fd71220bSRobert Mustacchi (void) vsnprintf(xpio->xp_errmsg, sizeof (xpio->xp_errmsg), fmt, ap);
145*fd71220bSRobert Mustacchi va_end(ap);
146*fd71220bSRobert Mustacchi return (false);
147*fd71220bSRobert Mustacchi }
148*fd71220bSRobert Mustacchi
149*fd71220bSRobert Mustacchi bool
xpio_update_error(xpio_gpio_update_t * update,xpio_update_err_t err,int32_t sys,const char * fmt,...)150*fd71220bSRobert Mustacchi xpio_update_error(xpio_gpio_update_t *update, xpio_update_err_t err,
151*fd71220bSRobert Mustacchi int32_t sys, const char *fmt, ...)
152*fd71220bSRobert Mustacchi {
153*fd71220bSRobert Mustacchi va_list ap;
154*fd71220bSRobert Mustacchi
155*fd71220bSRobert Mustacchi update->xgo_err = err;
156*fd71220bSRobert Mustacchi update->xgo_syserr = sys;
157*fd71220bSRobert Mustacchi va_start(ap, fmt);
158*fd71220bSRobert Mustacchi (void) vsnprintf(update->xgo_errmsg, sizeof (update->xgo_errmsg), fmt,
159*fd71220bSRobert Mustacchi ap);
160*fd71220bSRobert Mustacchi va_end(ap);
161*fd71220bSRobert Mustacchi return (false);
162*fd71220bSRobert Mustacchi }
163*fd71220bSRobert Mustacchi bool
xpio_success(xpio_t * xpio)164*fd71220bSRobert Mustacchi xpio_success(xpio_t *xpio)
165*fd71220bSRobert Mustacchi {
166*fd71220bSRobert Mustacchi xpio->xp_err = XPIO_ERR_OK;
167*fd71220bSRobert Mustacchi xpio->xp_syserr = 0;
168*fd71220bSRobert Mustacchi xpio->xp_errmsg[0] = '\0';
169*fd71220bSRobert Mustacchi return (true);
170*fd71220bSRobert Mustacchi }
171*fd71220bSRobert Mustacchi
172*fd71220bSRobert Mustacchi bool
xpio_update_success(xpio_gpio_update_t * update)173*fd71220bSRobert Mustacchi xpio_update_success(xpio_gpio_update_t *update)
174*fd71220bSRobert Mustacchi {
175*fd71220bSRobert Mustacchi update->xgo_err = XPIO_UPDATE_ERR_OK;
176*fd71220bSRobert Mustacchi update->xgo_syserr = 0;
177*fd71220bSRobert Mustacchi update->xgo_errmsg[0] = '\0';
178*fd71220bSRobert Mustacchi return (true);
179*fd71220bSRobert Mustacchi }
180*fd71220bSRobert Mustacchi
181*fd71220bSRobert Mustacchi typedef struct {
182*fd71220bSRobert Mustacchi xpio_t *xcc_xpio;
183*fd71220bSRobert Mustacchi xpio_ctrl_disc_f xcc_func;
184*fd71220bSRobert Mustacchi void *xcc_arg;
185*fd71220bSRobert Mustacchi } xpio_ctrl_cb_t;
186*fd71220bSRobert Mustacchi
187*fd71220bSRobert Mustacchi static int
xpio_ctrl_discover_cb(di_node_t di,di_minor_t minor,void * arg)188*fd71220bSRobert Mustacchi xpio_ctrl_discover_cb(di_node_t di, di_minor_t minor, void *arg)
189*fd71220bSRobert Mustacchi {
190*fd71220bSRobert Mustacchi bool ret;
191*fd71220bSRobert Mustacchi xpio_ctrl_cb_t *cb = arg;
192*fd71220bSRobert Mustacchi xpio_ctrl_disc_t disc;
193*fd71220bSRobert Mustacchi
194*fd71220bSRobert Mustacchi disc.xcd_minor = minor;
195*fd71220bSRobert Mustacchi
196*fd71220bSRobert Mustacchi ret = cb->xcc_func(cb->xcc_xpio, &disc, cb->xcc_arg);
197*fd71220bSRobert Mustacchi if (ret) {
198*fd71220bSRobert Mustacchi return (DI_WALK_CONTINUE);
199*fd71220bSRobert Mustacchi } else {
200*fd71220bSRobert Mustacchi return (DI_WALK_TERMINATE);
201*fd71220bSRobert Mustacchi }
202*fd71220bSRobert Mustacchi }
203*fd71220bSRobert Mustacchi
204*fd71220bSRobert Mustacchi void
xpio_ctrl_discover(xpio_t * xpio,xpio_ctrl_disc_f func,void * arg)205*fd71220bSRobert Mustacchi xpio_ctrl_discover(xpio_t *xpio, xpio_ctrl_disc_f func, void *arg)
206*fd71220bSRobert Mustacchi {
207*fd71220bSRobert Mustacchi xpio_ctrl_cb_t cb;
208*fd71220bSRobert Mustacchi
209*fd71220bSRobert Mustacchi cb.xcc_xpio = xpio;
210*fd71220bSRobert Mustacchi cb.xcc_func = func;
211*fd71220bSRobert Mustacchi cb.xcc_arg = arg;
212*fd71220bSRobert Mustacchi (void) di_walk_minor(xpio->xp_devinfo, DDI_NT_GPIO_CTRL, 0, &cb,
213*fd71220bSRobert Mustacchi xpio_ctrl_discover_cb);
214*fd71220bSRobert Mustacchi }
215*fd71220bSRobert Mustacchi
216*fd71220bSRobert Mustacchi void
xpio_ctrl_fini(xpio_ctrl_t * ctrl)217*fd71220bSRobert Mustacchi xpio_ctrl_fini(xpio_ctrl_t *ctrl)
218*fd71220bSRobert Mustacchi {
219*fd71220bSRobert Mustacchi if (ctrl == NULL) {
220*fd71220bSRobert Mustacchi return;
221*fd71220bSRobert Mustacchi }
222*fd71220bSRobert Mustacchi
223*fd71220bSRobert Mustacchi if (ctrl->xc_fd >= 0) {
224*fd71220bSRobert Mustacchi (void) close(ctrl->xc_fd);
225*fd71220bSRobert Mustacchi ctrl->xc_fd = -1;
226*fd71220bSRobert Mustacchi }
227*fd71220bSRobert Mustacchi
228*fd71220bSRobert Mustacchi free(ctrl);
229*fd71220bSRobert Mustacchi }
230*fd71220bSRobert Mustacchi
231*fd71220bSRobert Mustacchi void
xpio_ctrl_info_free(xpio_ctrl_info_t * infop)232*fd71220bSRobert Mustacchi xpio_ctrl_info_free(xpio_ctrl_info_t *infop)
233*fd71220bSRobert Mustacchi {
234*fd71220bSRobert Mustacchi free(infop);
235*fd71220bSRobert Mustacchi }
236*fd71220bSRobert Mustacchi
237*fd71220bSRobert Mustacchi uint32_t
xpio_ctrl_info_ngpios(xpio_ctrl_info_t * infop)238*fd71220bSRobert Mustacchi xpio_ctrl_info_ngpios(xpio_ctrl_info_t *infop)
239*fd71220bSRobert Mustacchi {
240*fd71220bSRobert Mustacchi return (infop->xci_ngpios);
241*fd71220bSRobert Mustacchi }
242*fd71220bSRobert Mustacchi
243*fd71220bSRobert Mustacchi uint32_t
xpio_ctrl_info_ndpios(xpio_ctrl_info_t * infop)244*fd71220bSRobert Mustacchi xpio_ctrl_info_ndpios(xpio_ctrl_info_t *infop)
245*fd71220bSRobert Mustacchi {
246*fd71220bSRobert Mustacchi return (infop->xci_ndpios);
247*fd71220bSRobert Mustacchi }
248*fd71220bSRobert Mustacchi
249*fd71220bSRobert Mustacchi const char *
xpio_ctrl_info_devpath(xpio_ctrl_info_t * infop)250*fd71220bSRobert Mustacchi xpio_ctrl_info_devpath(xpio_ctrl_info_t *infop)
251*fd71220bSRobert Mustacchi {
252*fd71220bSRobert Mustacchi return (infop->xci_devpath);
253*fd71220bSRobert Mustacchi }
254*fd71220bSRobert Mustacchi
255*fd71220bSRobert Mustacchi bool
xpio_ctrl_info(xpio_ctrl_t * ctrl,xpio_ctrl_info_t ** outp)256*fd71220bSRobert Mustacchi xpio_ctrl_info(xpio_ctrl_t *ctrl, xpio_ctrl_info_t **outp)
257*fd71220bSRobert Mustacchi {
258*fd71220bSRobert Mustacchi kgpio_ctrl_info_t info;
259*fd71220bSRobert Mustacchi xpio_t *xpio = ctrl->xc_xpio;
260*fd71220bSRobert Mustacchi xpio_ctrl_info_t *out;
261*fd71220bSRobert Mustacchi
262*fd71220bSRobert Mustacchi if (outp == NULL) {
263*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
264*fd71220bSRobert Mustacchi "invalid xpio_ctrl_info_t output pointer: %p", outp));
265*fd71220bSRobert Mustacchi }
266*fd71220bSRobert Mustacchi
267*fd71220bSRobert Mustacchi (void) memset(&info, 0, sizeof (info));
268*fd71220bSRobert Mustacchi if (ioctl(ctrl->xc_fd, KGPIO_IOC_CTRL_INFO, &info) != 0) {
269*fd71220bSRobert Mustacchi int e = errno;
270*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_KGPIO, e, "failed to issue "
271*fd71220bSRobert Mustacchi "controller information ioctl to %s: %s", ctrl->xc_name,
272*fd71220bSRobert Mustacchi strerror(e)));
273*fd71220bSRobert Mustacchi }
274*fd71220bSRobert Mustacchi
275*fd71220bSRobert Mustacchi out = calloc(1, sizeof (xpio_ctrl_info_t));
276*fd71220bSRobert Mustacchi if (out == NULL) {
277*fd71220bSRobert Mustacchi int e = errno;
278*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_NO_MEM, e, "failed to "
279*fd71220bSRobert Mustacchi "allocate memory for a new xpio_ctrl_info_t: %s",
280*fd71220bSRobert Mustacchi strerror(e)));
281*fd71220bSRobert Mustacchi }
282*fd71220bSRobert Mustacchi
283*fd71220bSRobert Mustacchi out->xci_ngpios = info.kci_ngpios;
284*fd71220bSRobert Mustacchi out->xci_ndpios = info.kci_ndpios;
285*fd71220bSRobert Mustacchi (void) memcpy(out->xci_devpath, info.kci_devpath,
286*fd71220bSRobert Mustacchi sizeof (info.kci_devpath));
287*fd71220bSRobert Mustacchi
288*fd71220bSRobert Mustacchi *outp = out;
289*fd71220bSRobert Mustacchi return (xpio_success(xpio));
290*fd71220bSRobert Mustacchi }
291*fd71220bSRobert Mustacchi
292*fd71220bSRobert Mustacchi bool
xpio_ctrl_init(xpio_t * xpio,di_minor_t minor,xpio_ctrl_t ** outp)293*fd71220bSRobert Mustacchi xpio_ctrl_init(xpio_t *xpio, di_minor_t minor, xpio_ctrl_t **outp)
294*fd71220bSRobert Mustacchi {
295*fd71220bSRobert Mustacchi xpio_ctrl_t *ctrl;
296*fd71220bSRobert Mustacchi char *path, buf[PATH_MAX];
297*fd71220bSRobert Mustacchi
298*fd71220bSRobert Mustacchi if (minor == DI_NODE_NIL) {
299*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
300*fd71220bSRobert Mustacchi "invalid di_minor_t: %p", minor));
301*fd71220bSRobert Mustacchi }
302*fd71220bSRobert Mustacchi
303*fd71220bSRobert Mustacchi if (outp == NULL) {
304*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
305*fd71220bSRobert Mustacchi "invalid xpio_ctrl_t output pointer: %p", outp));
306*fd71220bSRobert Mustacchi }
307*fd71220bSRobert Mustacchi *outp = NULL;
308*fd71220bSRobert Mustacchi
309*fd71220bSRobert Mustacchi if (strcmp(di_minor_nodetype(minor), DDI_NT_GPIO_CTRL) != 0) {
310*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_WRONG_MINOR_TYPE, 0,
311*fd71220bSRobert Mustacchi "minor %s has incorrect node type: %s, expected %s",
312*fd71220bSRobert Mustacchi di_minor_name(minor), di_minor_nodetype(minor),
313*fd71220bSRobert Mustacchi DDI_NT_GPIO_CTRL));
314*fd71220bSRobert Mustacchi }
315*fd71220bSRobert Mustacchi
316*fd71220bSRobert Mustacchi path = di_devfs_minor_path(minor);
317*fd71220bSRobert Mustacchi if (path == NULL) {
318*fd71220bSRobert Mustacchi int e = errno;
319*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_LIBDEVINFO, e, "failed to "
320*fd71220bSRobert Mustacchi "obtain /devices path for the requested minor: %s",
321*fd71220bSRobert Mustacchi strerror(e)));
322*fd71220bSRobert Mustacchi }
323*fd71220bSRobert Mustacchi
324*fd71220bSRobert Mustacchi if (snprintf(buf, sizeof (buf), "/devices%s", path) >= sizeof (buf)) {
325*fd71220bSRobert Mustacchi di_devfs_path_free(path);
326*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_INTERNAL, 0, "failed to "
327*fd71220bSRobert Mustacchi "construct full /devices minor path, would have overflown "
328*fd71220bSRobert Mustacchi "internal buffer"));
329*fd71220bSRobert Mustacchi }
330*fd71220bSRobert Mustacchi di_devfs_path_free(path);
331*fd71220bSRobert Mustacchi
332*fd71220bSRobert Mustacchi ctrl = calloc(1, sizeof (*ctrl));
333*fd71220bSRobert Mustacchi if (ctrl == NULL) {
334*fd71220bSRobert Mustacchi int e = errno;
335*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_NO_MEM, e, "failed to "
336*fd71220bSRobert Mustacchi "allocate memory for a new xpio_ctrl_t: %s", strerror(e)));
337*fd71220bSRobert Mustacchi }
338*fd71220bSRobert Mustacchi
339*fd71220bSRobert Mustacchi ctrl->xc_xpio = xpio;
340*fd71220bSRobert Mustacchi ctrl->xc_minor = minor;
341*fd71220bSRobert Mustacchi ctrl->xc_name = di_minor_name(minor);
342*fd71220bSRobert Mustacchi
343*fd71220bSRobert Mustacchi ctrl->xc_fd = open(buf, O_RDWR);
344*fd71220bSRobert Mustacchi if (ctrl->xc_fd < 0) {
345*fd71220bSRobert Mustacchi int e = errno;
346*fd71220bSRobert Mustacchi xpio_ctrl_fini(ctrl);
347*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_OPEN_DEV, e, "failed to open "
348*fd71220bSRobert Mustacchi "device path %s: %s", buf, strerror(e)));
349*fd71220bSRobert Mustacchi }
350*fd71220bSRobert Mustacchi
351*fd71220bSRobert Mustacchi *outp = ctrl;
352*fd71220bSRobert Mustacchi return (xpio_success(xpio));
353*fd71220bSRobert Mustacchi }
354*fd71220bSRobert Mustacchi
355*fd71220bSRobert Mustacchi typedef struct {
356*fd71220bSRobert Mustacchi bool xcia_found;
357*fd71220bSRobert Mustacchi const char *xcia_name;
358*fd71220bSRobert Mustacchi xpio_ctrl_t *xcia_ctrl;
359*fd71220bSRobert Mustacchi } xpio_ctrl_init_arg_t;
360*fd71220bSRobert Mustacchi
361*fd71220bSRobert Mustacchi static bool
xpio_ctrl_init_by_name_cb(xpio_t * xpio,xpio_ctrl_disc_t * disc,void * arg)362*fd71220bSRobert Mustacchi xpio_ctrl_init_by_name_cb(xpio_t *xpio, xpio_ctrl_disc_t *disc, void *arg)
363*fd71220bSRobert Mustacchi {
364*fd71220bSRobert Mustacchi xpio_ctrl_init_arg_t *init = arg;
365*fd71220bSRobert Mustacchi
366*fd71220bSRobert Mustacchi if (strcmp(di_minor_name(disc->xcd_minor), init->xcia_name) != 0) {
367*fd71220bSRobert Mustacchi return (true);
368*fd71220bSRobert Mustacchi }
369*fd71220bSRobert Mustacchi
370*fd71220bSRobert Mustacchi /*
371*fd71220bSRobert Mustacchi * As we've found a match. Attempt to open it. Whether we succeed or
372*fd71220bSRobert Mustacchi * fail, we're done at this point.
373*fd71220bSRobert Mustacchi */
374*fd71220bSRobert Mustacchi init->xcia_found = true;
375*fd71220bSRobert Mustacchi (void) xpio_ctrl_init(xpio, disc->xcd_minor, &init->xcia_ctrl);
376*fd71220bSRobert Mustacchi return (false);
377*fd71220bSRobert Mustacchi }
378*fd71220bSRobert Mustacchi
379*fd71220bSRobert Mustacchi bool
xpio_ctrl_init_by_name(xpio_t * xpio,const char * name,xpio_ctrl_t ** outp)380*fd71220bSRobert Mustacchi xpio_ctrl_init_by_name(xpio_t *xpio, const char *name, xpio_ctrl_t **outp)
381*fd71220bSRobert Mustacchi {
382*fd71220bSRobert Mustacchi xpio_ctrl_init_arg_t init;
383*fd71220bSRobert Mustacchi
384*fd71220bSRobert Mustacchi if (name == NULL) {
385*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
386*fd71220bSRobert Mustacchi "invalid name pointer: %p", name));
387*fd71220bSRobert Mustacchi }
388*fd71220bSRobert Mustacchi
389*fd71220bSRobert Mustacchi if (outp == NULL) {
390*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
391*fd71220bSRobert Mustacchi "invalid xpio_crl_t output pointer: %p", outp));
392*fd71220bSRobert Mustacchi }
393*fd71220bSRobert Mustacchi *outp = NULL;
394*fd71220bSRobert Mustacchi
395*fd71220bSRobert Mustacchi init.xcia_found = false;
396*fd71220bSRobert Mustacchi init.xcia_name = name;
397*fd71220bSRobert Mustacchi init.xcia_ctrl = NULL;
398*fd71220bSRobert Mustacchi
399*fd71220bSRobert Mustacchi xpio_ctrl_discover(xpio, xpio_ctrl_init_by_name_cb, &init);
400*fd71220bSRobert Mustacchi if (!init.xcia_found) {
401*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_CTRL_NAME, 0, "failed to "
402*fd71220bSRobert Mustacchi "find controller %s", init.xcia_name));
403*fd71220bSRobert Mustacchi }
404*fd71220bSRobert Mustacchi
405*fd71220bSRobert Mustacchi /*
406*fd71220bSRobert Mustacchi * If we have a NULL controller, but it was found, then we know that
407*fd71220bSRobert Mustacchi * this exists and instead had an error.
408*fd71220bSRobert Mustacchi */
409*fd71220bSRobert Mustacchi if (init.xcia_ctrl == NULL) {
410*fd71220bSRobert Mustacchi return (false);
411*fd71220bSRobert Mustacchi }
412*fd71220bSRobert Mustacchi
413*fd71220bSRobert Mustacchi *outp = init.xcia_ctrl;
414*fd71220bSRobert Mustacchi return (xpio_success(xpio));
415*fd71220bSRobert Mustacchi }
416*fd71220bSRobert Mustacchi
417*fd71220bSRobert Mustacchi void
xpio_gpio_info_free(xpio_gpio_info_t * gi)418*fd71220bSRobert Mustacchi xpio_gpio_info_free(xpio_gpio_info_t *gi)
419*fd71220bSRobert Mustacchi {
420*fd71220bSRobert Mustacchi if (gi == NULL) {
421*fd71220bSRobert Mustacchi return;
422*fd71220bSRobert Mustacchi }
423*fd71220bSRobert Mustacchi
424*fd71220bSRobert Mustacchi nvlist_free(gi->xgi_nvl);
425*fd71220bSRobert Mustacchi free(gi);
426*fd71220bSRobert Mustacchi }
427*fd71220bSRobert Mustacchi
428*fd71220bSRobert Mustacchi uint32_t
xpio_gpio_id(xpio_gpio_info_t * gi)429*fd71220bSRobert Mustacchi xpio_gpio_id(xpio_gpio_info_t *gi)
430*fd71220bSRobert Mustacchi {
431*fd71220bSRobert Mustacchi return (gi->xgi_id);
432*fd71220bSRobert Mustacchi }
433*fd71220bSRobert Mustacchi
434*fd71220bSRobert Mustacchi bool
xpio_gpio_info(xpio_ctrl_t * ctrl,uint32_t gpio_num,xpio_gpio_info_t ** outp)435*fd71220bSRobert Mustacchi xpio_gpio_info(xpio_ctrl_t *ctrl, uint32_t gpio_num, xpio_gpio_info_t **outp)
436*fd71220bSRobert Mustacchi {
437*fd71220bSRobert Mustacchi xpio_t *xpio = ctrl->xc_xpio;
438*fd71220bSRobert Mustacchi char *nvl_buf = NULL;
439*fd71220bSRobert Mustacchi kgpio_gpio_info_t info;
440*fd71220bSRobert Mustacchi bool ret;
441*fd71220bSRobert Mustacchi int nvl_ret;
442*fd71220bSRobert Mustacchi xpio_gpio_info_t *gi;
443*fd71220bSRobert Mustacchi
444*fd71220bSRobert Mustacchi if (outp == NULL) {
445*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
446*fd71220bSRobert Mustacchi "invalid xpio_gpio_info_t output pointer: %p", outp));
447*fd71220bSRobert Mustacchi
448*fd71220bSRobert Mustacchi }
449*fd71220bSRobert Mustacchi
450*fd71220bSRobert Mustacchi nvl_buf = malloc(XPIO_NVL_LEN);
451*fd71220bSRobert Mustacchi if (nvl_buf == NULL) {
452*fd71220bSRobert Mustacchi int e = errno;
453*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_NO_MEM, e, "failed to "
454*fd71220bSRobert Mustacchi "allocate memory for temporary data: %s", strerror(e)));
455*fd71220bSRobert Mustacchi }
456*fd71220bSRobert Mustacchi
457*fd71220bSRobert Mustacchi (void) memset(&info, 0, sizeof (info));
458*fd71220bSRobert Mustacchi info.kgi_id = gpio_num;
459*fd71220bSRobert Mustacchi info.kgi_attr = (uintptr_t)nvl_buf;
460*fd71220bSRobert Mustacchi info.kgi_attr_len = XPIO_NVL_LEN;
461*fd71220bSRobert Mustacchi
462*fd71220bSRobert Mustacchi if (ioctl(ctrl->xc_fd, KGPIO_IOC_GPIO_INFO, &info) != 0) {
463*fd71220bSRobert Mustacchi int e = errno;
464*fd71220bSRobert Mustacchi
465*fd71220bSRobert Mustacchi switch (e) {
466*fd71220bSRobert Mustacchi case ENOENT:
467*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_BAD_GPIO_ID, 0, "gpio "
468*fd71220bSRobert Mustacchi "%u does is not a valid GPIO for controller %s",
469*fd71220bSRobert Mustacchi gpio_num, ctrl->xc_name);
470*fd71220bSRobert Mustacchi break;
471*fd71220bSRobert Mustacchi case EOVERFLOW:
472*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_INTERNAL, 0,
473*fd71220bSRobert Mustacchi "internal error occurred: serialized nvlist "
474*fd71220bSRobert Mustacchi "exceeds library capabilities: wanted %zu bytes",
475*fd71220bSRobert Mustacchi info.kgi_attr_len);
476*fd71220bSRobert Mustacchi break;
477*fd71220bSRobert Mustacchi case EFAULT:
478*fd71220bSRobert Mustacchi abort();
479*fd71220bSRobert Mustacchi default:
480*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_KGPIO, e, "failed to "
481*fd71220bSRobert Mustacchi "issue gpio information ioctl for gpio %u: %s",
482*fd71220bSRobert Mustacchi gpio_num, strerror(e));
483*fd71220bSRobert Mustacchi break;
484*fd71220bSRobert Mustacchi }
485*fd71220bSRobert Mustacchi goto out;
486*fd71220bSRobert Mustacchi }
487*fd71220bSRobert Mustacchi
488*fd71220bSRobert Mustacchi gi = calloc(1, sizeof (xpio_gpio_info_t));
489*fd71220bSRobert Mustacchi if (gi == NULL) {
490*fd71220bSRobert Mustacchi int e = errno;
491*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_NO_MEM, e, "failed to "
492*fd71220bSRobert Mustacchi "allocate memory for a xpio_gpio_info_t: %s", strerror(e));
493*fd71220bSRobert Mustacchi goto out;
494*fd71220bSRobert Mustacchi }
495*fd71220bSRobert Mustacchi
496*fd71220bSRobert Mustacchi gi->xgi_flags = info.kgi_flags;
497*fd71220bSRobert Mustacchi gi->xgi_id = gpio_num;
498*fd71220bSRobert Mustacchi nvl_ret = nvlist_unpack(nvl_buf, info.kgi_attr_len, &gi->xgi_nvl, 0);
499*fd71220bSRobert Mustacchi if (nvl_ret != 0) {
500*fd71220bSRobert Mustacchi free(gi);
501*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_INTERNAL, nvl_ret, "kernel "
502*fd71220bSRobert Mustacchi "gave us an unparseable nvlist_t: %s", strerror(nvl_ret));
503*fd71220bSRobert Mustacchi } else {
504*fd71220bSRobert Mustacchi *outp = gi;
505*fd71220bSRobert Mustacchi ret = xpio_success(xpio);
506*fd71220bSRobert Mustacchi }
507*fd71220bSRobert Mustacchi out:
508*fd71220bSRobert Mustacchi free(nvl_buf);
509*fd71220bSRobert Mustacchi return (ret);
510*fd71220bSRobert Mustacchi }
511*fd71220bSRobert Mustacchi
512*fd71220bSRobert Mustacchi void
xpio_gpio_update_free(xpio_gpio_update_t * update)513*fd71220bSRobert Mustacchi xpio_gpio_update_free(xpio_gpio_update_t *update)
514*fd71220bSRobert Mustacchi {
515*fd71220bSRobert Mustacchi if (update == NULL) {
516*fd71220bSRobert Mustacchi return;
517*fd71220bSRobert Mustacchi }
518*fd71220bSRobert Mustacchi
519*fd71220bSRobert Mustacchi if (update->xgo_update != NULL) {
520*fd71220bSRobert Mustacchi nvlist_free(update->xgo_update);
521*fd71220bSRobert Mustacchi update->xgo_update = NULL;
522*fd71220bSRobert Mustacchi }
523*fd71220bSRobert Mustacchi
524*fd71220bSRobert Mustacchi if (update->xgo_err_nvl != NULL) {
525*fd71220bSRobert Mustacchi nvlist_free(update->xgo_err_nvl);
526*fd71220bSRobert Mustacchi update->xgo_err_nvl = NULL;
527*fd71220bSRobert Mustacchi }
528*fd71220bSRobert Mustacchi
529*fd71220bSRobert Mustacchi free(update);
530*fd71220bSRobert Mustacchi }
531*fd71220bSRobert Mustacchi
532*fd71220bSRobert Mustacchi bool
xpio_gpio_update(xpio_ctrl_t * ctrl,xpio_gpio_update_t * update)533*fd71220bSRobert Mustacchi xpio_gpio_update(xpio_ctrl_t *ctrl, xpio_gpio_update_t *update)
534*fd71220bSRobert Mustacchi {
535*fd71220bSRobert Mustacchi xpio_t *xpio = ctrl->xc_xpio;
536*fd71220bSRobert Mustacchi int nvl_ret;
537*fd71220bSRobert Mustacchi kgpio_update_t kgu;
538*fd71220bSRobert Mustacchi size_t pack_size;
539*fd71220bSRobert Mustacchi bool ret;
540*fd71220bSRobert Mustacchi char *update_buf = NULL, *err_buf = NULL;
541*fd71220bSRobert Mustacchi
542*fd71220bSRobert Mustacchi if (update == NULL) {
543*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
544*fd71220bSRobert Mustacchi "invalid xpio_gpio_update_t pointer: %p", update));
545*fd71220bSRobert Mustacchi }
546*fd71220bSRobert Mustacchi
547*fd71220bSRobert Mustacchi if (update->xgo_err_nvl != NULL) {
548*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_UPDATE_USED, 0, "this "
549*fd71220bSRobert Mustacchi "update structure was already used and has error "
550*fd71220bSRobert Mustacchi "information associated with it"));
551*fd71220bSRobert Mustacchi }
552*fd71220bSRobert Mustacchi
553*fd71220bSRobert Mustacchi nvl_ret = nvlist_size(update->xgo_update, &pack_size, NV_ENCODE_NATIVE);
554*fd71220bSRobert Mustacchi if (nvl_ret != 0) {
555*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_INTERNAL, nvl_ret, "failed "
556*fd71220bSRobert Mustacchi "to determine packed update nvlist_t size: %s",
557*fd71220bSRobert Mustacchi strerror(nvl_ret)));
558*fd71220bSRobert Mustacchi }
559*fd71220bSRobert Mustacchi
560*fd71220bSRobert Mustacchi update_buf = malloc(pack_size);
561*fd71220bSRobert Mustacchi if (update_buf == NULL) {
562*fd71220bSRobert Mustacchi int e = errno;
563*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_NO_MEM, e, "failed to allocate "
564*fd71220bSRobert Mustacchi "%zu bytes for the packed nvlist buffer: %s", pack_size,
565*fd71220bSRobert Mustacchi strerror(e));
566*fd71220bSRobert Mustacchi goto out;
567*fd71220bSRobert Mustacchi }
568*fd71220bSRobert Mustacchi
569*fd71220bSRobert Mustacchi err_buf = malloc(XPIO_NVL_LEN);
570*fd71220bSRobert Mustacchi if (err_buf == NULL) {
571*fd71220bSRobert Mustacchi int e = errno;
572*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_NO_MEM, e, "failed to allocate "
573*fd71220bSRobert Mustacchi "%u bytes for the packed error buffer: %s", XPIO_NVL_LEN,
574*fd71220bSRobert Mustacchi strerror(e));
575*fd71220bSRobert Mustacchi goto out;
576*fd71220bSRobert Mustacchi }
577*fd71220bSRobert Mustacchi
578*fd71220bSRobert Mustacchi nvl_ret = nvlist_pack(update->xgo_update, &update_buf, &pack_size,
579*fd71220bSRobert Mustacchi NV_ENCODE_NATIVE, 0);
580*fd71220bSRobert Mustacchi if (nvl_ret != 0) {
581*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_INTERNAL, nvl_ret, "failed to "
582*fd71220bSRobert Mustacchi "pack update data: %s", strerror(nvl_ret));
583*fd71220bSRobert Mustacchi goto out;
584*fd71220bSRobert Mustacchi }
585*fd71220bSRobert Mustacchi
586*fd71220bSRobert Mustacchi (void) memset(&kgu, '\0', sizeof (kgpio_update_t));
587*fd71220bSRobert Mustacchi kgu.kgu_id = update->xgo_gpio->xgi_id;
588*fd71220bSRobert Mustacchi kgu.kgu_attr = (uintptr_t)update_buf;
589*fd71220bSRobert Mustacchi kgu.kgu_attr_len = pack_size;
590*fd71220bSRobert Mustacchi kgu.kgu_err = (uintptr_t)err_buf;
591*fd71220bSRobert Mustacchi kgu.kgu_err_len = XPIO_NVL_LEN;
592*fd71220bSRobert Mustacchi
593*fd71220bSRobert Mustacchi if (ioctl(ctrl->xc_fd, KGPIO_IOC_GPIO_UPDATE, &kgu) != 0) {
594*fd71220bSRobert Mustacchi int e = errno;
595*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_KGPIO, e, "failed to isue "
596*fd71220bSRobert Mustacchi "gpio attribute update ioctl to %s, %u: %s", ctrl->xc_name,
597*fd71220bSRobert Mustacchi update->xgo_gpio->xgi_id, strerror(e));
598*fd71220bSRobert Mustacchi goto out;
599*fd71220bSRobert Mustacchi }
600*fd71220bSRobert Mustacchi
601*fd71220bSRobert Mustacchi /*
602*fd71220bSRobert Mustacchi * With no flags and a zero return value, this was successful. That's
603*fd71220bSRobert Mustacchi * good.
604*fd71220bSRobert Mustacchi */
605*fd71220bSRobert Mustacchi if (kgu.kgu_flags == 0) {
606*fd71220bSRobert Mustacchi ret = xpio_success(xpio);
607*fd71220bSRobert Mustacchi goto out;
608*fd71220bSRobert Mustacchi }
609*fd71220bSRobert Mustacchi
610*fd71220bSRobert Mustacchi /*
611*fd71220bSRobert Mustacchi * We should have packed information. Attempt to serialize it back into
612*fd71220bSRobert Mustacchi * an nvlist for allowing the user to understand what happened.
613*fd71220bSRobert Mustacchi */
614*fd71220bSRobert Mustacchi if ((kgu.kgu_flags & KGPIO_UPDATE_ERR_NVL_VALID) != 0) {
615*fd71220bSRobert Mustacchi nvl_ret = nvlist_unpack((char *)kgu.kgu_err, kgu.kgu_err_len,
616*fd71220bSRobert Mustacchi &update->xgo_err_nvl, 0);
617*fd71220bSRobert Mustacchi if (nvl_ret != 0) {
618*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_INTERNAL, nvl_ret,
619*fd71220bSRobert Mustacchi "kernel gave us an unparseable error nvlist_t for "
620*fd71220bSRobert Mustacchi "update failure: %s", strerror(nvl_ret));
621*fd71220bSRobert Mustacchi goto out;
622*fd71220bSRobert Mustacchi }
623*fd71220bSRobert Mustacchi }
624*fd71220bSRobert Mustacchi
625*fd71220bSRobert Mustacchi ret = xpio_error(xpio, XPIO_ERR_BAD_UPDATE, 0, "failed to apply GPIO "
626*fd71220bSRobert Mustacchi "update, invalid or unsupported attributes");
627*fd71220bSRobert Mustacchi out:
628*fd71220bSRobert Mustacchi free(update_buf);
629*fd71220bSRobert Mustacchi free(err_buf);
630*fd71220bSRobert Mustacchi return (ret);
631*fd71220bSRobert Mustacchi }
632*fd71220bSRobert Mustacchi
633*fd71220bSRobert Mustacchi bool
xpio_gpio_lookup_id(xpio_ctrl_t * ctrl,const char * name,uint32_t * idp)634*fd71220bSRobert Mustacchi xpio_gpio_lookup_id(xpio_ctrl_t *ctrl, const char *name, uint32_t *idp)
635*fd71220bSRobert Mustacchi {
636*fd71220bSRobert Mustacchi xpio_t *xpio = ctrl->xc_xpio;
637*fd71220bSRobert Mustacchi kgpio_ioc_name2id_t id;
638*fd71220bSRobert Mustacchi
639*fd71220bSRobert Mustacchi if (name == NULL) {
640*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
641*fd71220bSRobert Mustacchi "invalid name pointer: %p", name));
642*fd71220bSRobert Mustacchi }
643*fd71220bSRobert Mustacchi
644*fd71220bSRobert Mustacchi if (idp == NULL) {
645*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
646*fd71220bSRobert Mustacchi "invalid id pointer: %p", idp));
647*fd71220bSRobert Mustacchi }
648*fd71220bSRobert Mustacchi
649*fd71220bSRobert Mustacchi (void) memset(&id, 0, sizeof (id));
650*fd71220bSRobert Mustacchi
651*fd71220bSRobert Mustacchi if (strlcpy(id.kin_name, name, sizeof (id.kin_name)) >=
652*fd71220bSRobert Mustacchi sizeof (id.kin_name)) {
653*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_GPIO_NAME, 0, "GPIO name "
654*fd71220bSRobert Mustacchi "'%s' is too long and invalid", name));
655*fd71220bSRobert Mustacchi }
656*fd71220bSRobert Mustacchi
657*fd71220bSRobert Mustacchi if (ioctl(ctrl->xc_fd, KGPIO_IOC_GPIO_NAME2ID, &id) != 0) {
658*fd71220bSRobert Mustacchi int e = errno;
659*fd71220bSRobert Mustacchi switch (e) {
660*fd71220bSRobert Mustacchi case ENOENT:
661*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_NO_LOOKUP_MATCH, 0,
662*fd71220bSRobert Mustacchi "GPIO name '%s' is unknown on controller %s",
663*fd71220bSRobert Mustacchi name, ctrl->xc_name));
664*fd71220bSRobert Mustacchi case EINVAL:
665*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_GPIO_NAME, 0,
666*fd71220bSRobert Mustacchi "GPIO name '%s' is invalid", name));
667*fd71220bSRobert Mustacchi default:
668*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_KGPIO, e,
669*fd71220bSRobert Mustacchi "failed to issue GPIO name to GPIO id ioctl to "
670*fd71220bSRobert Mustacchi "%s: %s", ctrl->xc_name, strerror(e)));
671*fd71220bSRobert Mustacchi }
672*fd71220bSRobert Mustacchi }
673*fd71220bSRobert Mustacchi
674*fd71220bSRobert Mustacchi *idp = id.kin_id;
675*fd71220bSRobert Mustacchi return (xpio_success(xpio));
676*fd71220bSRobert Mustacchi }
677*fd71220bSRobert Mustacchi
678*fd71220bSRobert Mustacchi bool
xpio_gpio_update_init(xpio_t * xpio,xpio_gpio_info_t * gi,xpio_gpio_update_t ** outp)679*fd71220bSRobert Mustacchi xpio_gpio_update_init(xpio_t *xpio, xpio_gpio_info_t *gi,
680*fd71220bSRobert Mustacchi xpio_gpio_update_t **outp)
681*fd71220bSRobert Mustacchi {
682*fd71220bSRobert Mustacchi int ret;
683*fd71220bSRobert Mustacchi xpio_gpio_update_t *update;
684*fd71220bSRobert Mustacchi
685*fd71220bSRobert Mustacchi if (gi == NULL) {
686*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
687*fd71220bSRobert Mustacchi "invalid xpio_gpio_info_t pointer: %p", gi));
688*fd71220bSRobert Mustacchi }
689*fd71220bSRobert Mustacchi
690*fd71220bSRobert Mustacchi if (outp == NULL) {
691*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
692*fd71220bSRobert Mustacchi "invalid xpio_gpio_update_t output pointer: %p", outp));
693*fd71220bSRobert Mustacchi }
694*fd71220bSRobert Mustacchi
695*fd71220bSRobert Mustacchi update = calloc(1, sizeof (xpio_gpio_update_t));
696*fd71220bSRobert Mustacchi if (update == NULL) {
697*fd71220bSRobert Mustacchi int e = errno;
698*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_NO_MEM, e, "failed to "
699*fd71220bSRobert Mustacchi "allocate memory for xpio_gpio_update_t: %s", strerror(e)));
700*fd71220bSRobert Mustacchi }
701*fd71220bSRobert Mustacchi
702*fd71220bSRobert Mustacchi ret = nvlist_alloc(&update->xgo_update, NV_UNIQUE_NAME, 0);
703*fd71220bSRobert Mustacchi if (ret != 0) {
704*fd71220bSRobert Mustacchi free(update);
705*fd71220bSRobert Mustacchi if (ret == ENOMEM) {
706*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_NO_MEM, ret, "failed "
707*fd71220bSRobert Mustacchi "to allocate nvlist_t for xpio_gpio_update_t"));
708*fd71220bSRobert Mustacchi }
709*fd71220bSRobert Mustacchi
710*fd71220bSRobert Mustacchi return (xpio_error(xpio, XPIO_ERR_INTERNAL, ret, "failed to "
711*fd71220bSRobert Mustacchi "create nvlist_t for xpio_gpio_update_t: %s",
712*fd71220bSRobert Mustacchi strerror(ret)));
713*fd71220bSRobert Mustacchi }
714*fd71220bSRobert Mustacchi
715*fd71220bSRobert Mustacchi update->xgo_gpio = gi;
716*fd71220bSRobert Mustacchi *outp = update;
717*fd71220bSRobert Mustacchi return (xpio_success(xpio));
718*fd71220bSRobert Mustacchi }
719*fd71220bSRobert Mustacchi
720*fd71220bSRobert Mustacchi void
xpio_fini(xpio_t * xpio)721*fd71220bSRobert Mustacchi xpio_fini(xpio_t *xpio)
722*fd71220bSRobert Mustacchi {
723*fd71220bSRobert Mustacchi if (xpio == NULL)
724*fd71220bSRobert Mustacchi return;
725*fd71220bSRobert Mustacchi
726*fd71220bSRobert Mustacchi if (xpio->xp_devinfo != DI_NODE_NIL) {
727*fd71220bSRobert Mustacchi di_fini(xpio->xp_devinfo);
728*fd71220bSRobert Mustacchi xpio->xp_devinfo = NULL;
729*fd71220bSRobert Mustacchi }
730*fd71220bSRobert Mustacchi
731*fd71220bSRobert Mustacchi free(xpio);
732*fd71220bSRobert Mustacchi }
733*fd71220bSRobert Mustacchi
734*fd71220bSRobert Mustacchi xpio_t *
xpio_init(void)735*fd71220bSRobert Mustacchi xpio_init(void)
736*fd71220bSRobert Mustacchi {
737*fd71220bSRobert Mustacchi xpio_t *xpio;
738*fd71220bSRobert Mustacchi
739*fd71220bSRobert Mustacchi xpio = calloc(1, sizeof (xpio_t));
740*fd71220bSRobert Mustacchi if (xpio == NULL) {
741*fd71220bSRobert Mustacchi return (NULL);
742*fd71220bSRobert Mustacchi }
743*fd71220bSRobert Mustacchi xpio->xp_err = XPIO_ERR_OK;
744*fd71220bSRobert Mustacchi
745*fd71220bSRobert Mustacchi xpio->xp_devinfo = di_init("/", DINFOCPYALL);
746*fd71220bSRobert Mustacchi if (xpio->xp_devinfo == DI_NODE_NIL) {
747*fd71220bSRobert Mustacchi xpio_fini(xpio);
748*fd71220bSRobert Mustacchi return (NULL);
749*fd71220bSRobert Mustacchi }
750*fd71220bSRobert Mustacchi
751*fd71220bSRobert Mustacchi return (xpio);
752*fd71220bSRobert Mustacchi }
753