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