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 * This file implements all of the access to and manipulating of attributes. An 18 * attribute is a thinly veiled reference to the underlying nvlist_t of data 19 * that we were given. Attributes are treated as the underlying nvpair data. 20 * This gets us out of some allocation bits, but means that we need to always 21 * ask for the gpio information itself depending on what we're trying to do as 22 * that has a pointer to our nvlist. 23 */ 24 25 #include <strings.h> 26 #include <sys/gpio/zen_gpio.h> 27 #include <sys/gpio/gpio_sim.h> 28 #include <sys/sysmacros.h> 29 30 #include "libxpio_impl.h" 31 32 /* 33 * These are data tables that exist for each attribute. They provide a general 34 * means of mapping between a string and a known uint32_t value. Currently we 35 * assume that these strings do not need translation and localization. There 36 * should be one table of values which is then wrapped up inside something else. 37 */ 38 typedef struct { 39 uint32_t xp_val; 40 const char *xp_name; 41 } xpio_pair_t; 42 43 static const xpio_pair_t zen_gpio_pad_pairs[] = { 44 { ZEN_GPIO_PAD_TYPE_GPIO, "gpio" }, 45 { ZEN_GPIO_PAD_TYPE_SD, "sd" }, 46 { ZEN_GPIO_PAD_TYPE_I2C, "i2c" }, 47 { ZEN_GPIO_PAD_TYPE_I3C, "i3c" }, 48 { 0x00, NULL } 49 }; 50 51 static const xpio_pair_t zen_gpio_cap_pairs[] = { 52 { ZEN_GPIO_C_AGPIO, "AGPIO" }, 53 { ZEN_GPIO_C_REMOTE, "Remote" }, 54 { 0x00, NULL } 55 }; 56 57 static const xpio_pair_t zen_gpio_driver_pairs[] = { 58 { ZEN_GPIO_DRIVER_UNKNOWN, "unknown" }, 59 { ZEN_GPIO_DRIVER_PUSH_PULL, "push-pull" }, 60 { ZEN_GPIO_DRIVER_OPEN_DRAIN, "open-drain" }, 61 { 0x00, NULL } 62 }; 63 64 static const xpio_pair_t zen_gpio_output_pairs[] = { 65 { ZEN_GPIO_OUTPUT_DISABLED, "disabled" }, 66 { ZEN_GPIO_OUTPUT_LOW, "low" }, 67 { ZEN_GPIO_OUTPUT_HIGH, "high" }, 68 { 0x00, NULL } 69 }; 70 71 static const xpio_pair_t zen_gpio_input_pairs[] = { 72 { ZEN_GPIO_INPUT_LOW, "low" }, 73 { ZEN_GPIO_INPUT_HIGH, "high" }, 74 { 0x00, NULL } 75 }; 76 77 static const xpio_pair_t zen_gpio_voltage_pairs[] = { 78 { ZEN_GPIO_V_UNKNOWN, "unknown" }, 79 { ZEN_GPIO_V_1P1_S3, "1.1V" }, 80 { ZEN_GPIO_V_1P8_S5, "1.8V" }, 81 { ZEN_GPIO_V_1P8_S0, "1.8V" }, 82 { ZEN_GPIO_V_3P3_S5, "3.3V" }, 83 { ZEN_GPIO_V_3P3_S0, "3.3V" }, 84 { 0x00, NULL } 85 }; 86 87 static const xpio_pair_t zen_gpio_pull_pairs[] = { 88 { ZEN_GPIO_PULL_DISABLED, "disabled" }, 89 { ZEN_GPIO_PULL_DOWN, "down" }, 90 { ZEN_GPIO_PULL_UP_4K, "4k-up" }, 91 { ZEN_GPIO_PULL_UP_8K, "8k-up" }, 92 { ZEN_GPIO_PULL_UP, "up" }, 93 { ZEN_GPIO_PULL_DOWN_UP, "up|down" }, 94 { ZEN_GPIO_PULL_DOWN_UP_4K, "4k-up|down" }, 95 { ZEN_GPIO_PULL_DOWN_UP_8K, "8k-up|down" }, 96 { 0x00, NULL } 97 }; 98 99 static const xpio_pair_t zen_gpio_drive_pairs[] = { 100 { ZEN_GPIO_DRIVE_UNKNOWN, "unknown" }, 101 { ZEN_GPIO_DRIVE_40R, "40R" }, 102 { ZEN_GPIO_DRIVE_60R, "60R" }, 103 { ZEN_GPIO_DRIVE_80R, "80R" }, 104 { 0x00, NULL } 105 }; 106 107 static const xpio_pair_t zen_gpio_dbt_mode_pairs[] = { 108 { ZEN_GPIO_DEBOUNCE_MODE_NONE, "none" }, 109 { ZEN_GPIO_DEBOUNCE_MODE_KEEP_LOW, "keep-low-glitch" }, 110 { ZEN_GPIO_DEBOUNCE_MODE_KEEP_HIGH, "keep-high-glitch" }, 111 { ZEN_GPIO_DEBOUNCE_MODE_REMOVE, "remove-glitch" }, 112 { 0x00, NULL } 113 }; 114 115 static const xpio_pair_t zen_gpio_dbt_unit_pairs[] = { 116 { ZEN_GPIO_DEBOUNCE_UNIT_2RTC, "61us" }, 117 { ZEN_GPIO_DEBOUNCE_UNIT_8RTC, "244us" }, 118 { ZEN_GPIO_DEBOUNCE_UNIT_512RTC, "15.6ms" }, 119 { ZEN_GPIO_DEBOUNCE_UNIT_2048RTC, "62.5ms" }, 120 { 0x00, NULL } 121 }; 122 123 static const xpio_pair_t zen_gpio_trigger_mode_pairs[] = { 124 { ZEN_GPIO_TRIGGER_UNKNOWN, "unknown" }, 125 { ZEN_GPIO_TRIGGER_EDGE_HIGH, "edge/high" }, 126 { ZEN_GPIO_TRIGGER_EDGE_LOW, "edge/low" }, 127 { ZEN_GPIO_TRIGGER_EDGE_BOTH, "edge/both" }, 128 { ZEN_GPIO_TRIGGER_LEVEL_HIGH, "level/high" }, 129 { ZEN_GPIO_TRIGGER_LEVEL_LOW, "level/low" }, 130 { 0x00, NULL } 131 }; 132 133 static const xpio_pair_t zen_gpio_status_pairs[] = { 134 { ZEN_GPIO_STATUS_WAKE, "wake" }, 135 { ZEN_GPIO_STATUS_INTR, "interrupt" }, 136 { 0x00, NULL } 137 }; 138 139 static const xpio_pair_t gpio_sim_output_pairs[] = { 140 { GPIO_SIM_OUTPUT_DISABLED, "disabled" }, 141 { GPIO_SIM_OUTPUT_LOW, "low" }, 142 { GPIO_SIM_OUTPUT_HIGH, "high" }, 143 { 0x00, NULL } 144 }; 145 146 static const xpio_pair_t gpio_sim_input_pairs[] = { 147 { GPIO_SIM_INPUT_LOW, "low" }, 148 { GPIO_SIM_INPUT_HIGH, "high" }, 149 { 0x00, NULL } 150 }; 151 152 static const xpio_pair_t gpio_sim_pull_pairs[] = { 153 { GPIO_SIM_PULL_DISABLED, "disabled" }, 154 { GPIO_SIM_PULL_DOWN, "down" }, 155 { GPIO_SIM_PULL_DOWN_23K, "23k-down" }, 156 { GPIO_SIM_PULL_UP, "up" }, 157 { GPIO_SIM_PULL_UP_5K, "5k-up" }, 158 { GPIO_SIM_PULL_UP_40K, "40k-up" }, 159 { GPIO_SIM_PULL_BOTH, "up|down" }, 160 { 0x00, NULL } 161 }; 162 163 static const xpio_pair_t gpio_sim_voltage_pairs[] = { 164 { GPIO_SIM_VOLTAGE_1P8, "1.8V" }, 165 { GPIO_SIM_VOLTAGE_3P3, "3.3V" }, 166 { GPIO_SIM_VOLTAGE_12P0, "12.0V" }, 167 { GPIO_SIM_VOLTAGE_54P5, "54.5V" }, 168 { 0x00, NULL } 169 }; 170 171 static const xpio_pair_t gpio_sim_speed_pairs[] = { 172 { GPIO_SIM_SPEED_LOW, "low" }, 173 { GPIO_SIM_SPEED_MEDIUM, "medium" }, 174 { GPIO_SIM_SPEED_HIGH, "high" }, 175 { GPIO_SIM_SPEED_VERY_HIGH, "very-high" }, 176 { 0x00, NULL } 177 }; 178 179 /* 180 * These two different functions are intended for different uses. Basically 181 * today most attributes that providers expose are semantic enums that describe 182 * state. The tostr_f function pointer is intended for when translating from the 183 * provider's notion of it to a humans. The tou32_f is intended for translating 184 * from a human's notion to a providers. The latter translation still works for 185 * properties that are read-only, mainly because it is the provider's job to be 186 * the source of truth for what is read-only or not. 187 */ 188 typedef bool (*xpio_xlate_tostr_f)(const uint32_t, const xpio_pair_t *, char *, 189 size_t); 190 typedef bool (*xpio_xlate_tou32_f)(const char *, const xpio_pair_t *, 191 uint32_t *); 192 193 typedef struct { 194 const char *xt_name; 195 const xpio_pair_t *xt_pairs; 196 xpio_xlate_tostr_f xt_xlate_tostr; 197 xpio_xlate_tou32_f xt_xlate_tou32; 198 } xpio_translate_t; 199 200 static bool 201 xpio_attr_xlate_tostr_direct(const uint32_t val, const xpio_pair_t *pairs, 202 char *buf, size_t buflen) 203 { 204 for (uint_t i = 0; pairs[i].xp_name != NULL; i++) { 205 if (val == pairs[i].xp_val) { 206 return (strlcpy(buf, pairs[i].xp_name, buflen) < 207 buflen); 208 } 209 } 210 return (false); 211 } 212 213 static bool 214 xpio_attr_xlate_tou32_direct(const char *str, const xpio_pair_t *pairs, 215 uint32_t *outp) 216 { 217 for (uint_t i = 0; pairs[i].xp_name != NULL; i++) { 218 if (strcmp(str, pairs[i].xp_name) == 0) { 219 *outp = pairs[i].xp_val; 220 return (true); 221 } 222 } 223 return (false); 224 } 225 226 static bool 227 xpio_attr_xlate_tostr_bitfield(const uint32_t val, const xpio_pair_t *pairs, 228 char *buf, size_t buflen) 229 { 230 size_t off = 0; 231 bool first = true; 232 233 buf[0] = '\0'; 234 for (uint_t i = 0; pairs[i].xp_name != NULL; i++) { 235 int ret; 236 237 if ((pairs[i].xp_val & val) != pairs[i].xp_val) { 238 continue; 239 } 240 241 ret = snprintf(buf + off, buflen - off, "%s%s", 242 first ? "" : "|", pairs[i].xp_name); 243 if (ret >= (buflen - off)) { 244 return (false); 245 } 246 off += ret; 247 first = false; 248 } 249 250 return (true); 251 } 252 253 /* 254 * We expect a bit field to have a series of strings that are | delineated. This 255 * means that we need to search and only look at the portion of the string that 256 * matches the '|'. This leads to use needing to check two things for a match: 257 * 258 * o That a strncmp() with the found string length matches. 259 * o That the total length indicates the end of the pair's string. This must 260 * be done after the first check as the first check returning zero 261 * effectively gives us a guarantee on the pair's length and that the next 262 * byte is valid. 263 */ 264 static bool 265 xpio_attr_xlate_tou32_bitfield(const char *str, const xpio_pair_t *pairs, 266 uint32_t *outp) 267 { 268 *outp = 0; 269 bool found = false; 270 271 while (*str != '\0') { 272 size_t len; 273 const char *pipe = strchr(str, '|'); 274 bool match = false; 275 276 if (pipe != NULL) { 277 len = (uintptr_t)pipe - (uintptr_t)str; 278 } else { 279 len = strlen(str); 280 } 281 282 for (uint_t i = 0; pairs[i].xp_name != NULL; i++) { 283 if (strncmp(pairs[i].xp_name, str, len) == 0 && 284 pairs[i].xp_name[len] == '\0') { 285 found = true; 286 match = true; 287 *outp |= pairs[i].xp_val; 288 match = true; 289 break; 290 } 291 } 292 293 if (!match) { 294 return (false); 295 } 296 297 if (pipe != NULL) { 298 str = pipe + 1; 299 } else { 300 break; 301 } 302 } 303 304 return (found); 305 } 306 307 static bool 308 xpio_attr_xlate_tostr_hex(const uint32_t val, const xpio_pair_t *pairs, 309 char *buf, size_t buflen) 310 { 311 return (snprintf(buf, buflen, "0x%x", val) < buflen); 312 } 313 314 static bool 315 xpio_attr_xlate_tou32_hex(const char *str, const xpio_pair_t *pairs, 316 uint32_t *outp) 317 { 318 char *eptr; 319 unsigned long long l; 320 321 errno = 0; 322 l = strtoull(str, &eptr, 0); 323 if (errno != 0 || *eptr != '\0' || l > UINT32_MAX) { 324 return (false); 325 } 326 327 *outp = (uint32_t)l; 328 return (true); 329 } 330 331 static const xpio_translate_t xpio_attr_xlates[] = { 332 /* zen_gpio(4D) attrs */ 333 { ZEN_GPIO_ATTR_PAD_TYPE, zen_gpio_pad_pairs, 334 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 335 { ZEN_GPIO_ATTR_CAPS, zen_gpio_cap_pairs, 336 xpio_attr_xlate_tostr_bitfield, xpio_attr_xlate_tou32_bitfield }, 337 { ZEN_GPIO_ATTR_OUTPUT_DRIVER, zen_gpio_driver_pairs, 338 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 339 { ZEN_GPIO_ATTR_OUTPUT, zen_gpio_output_pairs, 340 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 341 { ZEN_GPIO_ATTR_INPUT, zen_gpio_input_pairs, 342 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 343 { ZEN_GPIO_ATTR_VOLTAGE, zen_gpio_voltage_pairs, 344 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 345 { ZEN_GPIO_ATTR_PULL, zen_gpio_pull_pairs, 346 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 347 { ZEN_GPIO_ATTR_DRIVE_STRENGTH, zen_gpio_drive_pairs, 348 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 349 { ZEN_GPIO_ATTR_DEBOUNCE_MODE, zen_gpio_dbt_mode_pairs, 350 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 351 { ZEN_GPIO_ATTR_DEBOUNCE_UNIT, zen_gpio_dbt_unit_pairs, 352 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 353 { ZEN_GPIO_ATTR_DEBOUNCE_COUNT, NULL, xpio_attr_xlate_tostr_hex, 354 xpio_attr_xlate_tou32_hex }, 355 { ZEN_GPIO_ATTR_TRIGGER_MODE, zen_gpio_trigger_mode_pairs, 356 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 357 { ZEN_GPIO_ATTR_STATUS, zen_gpio_status_pairs, 358 xpio_attr_xlate_tostr_bitfield, xpio_attr_xlate_tou32_bitfield }, 359 { ZEN_GPIO_ATTR_RAW_REG, NULL, xpio_attr_xlate_tostr_hex, 360 xpio_attr_xlate_tou32_hex }, 361 /* gpio_sim(4D) attrs */ 362 { GPIO_SIM_ATTR_OUTPUT, gpio_sim_output_pairs, 363 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 364 { GPIO_SIM_ATTR_INPUT, gpio_sim_input_pairs, 365 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 366 { GPIO_SIM_ATTR_PULL, gpio_sim_pull_pairs, 367 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 368 { GPIO_SIM_ATTR_VOLTAGE, gpio_sim_voltage_pairs, 369 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 370 { GPIO_SIM_ATTR_SPEED, gpio_sim_speed_pairs, 371 xpio_attr_xlate_tostr_direct, xpio_attr_xlate_tou32_direct }, 372 }; 373 374 bool 375 xpio_gpio_attr_xlate_uint32_to_str(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr, 376 uint32_t val, char *buf, size_t buflen) 377 { 378 const char *name = xpio_gpio_attr_name(gi, attr); 379 380 for (size_t i = 0; i < ARRAY_SIZE(xpio_attr_xlates); i++) { 381 if (strcmp(name, xpio_attr_xlates[i].xt_name) != 0) 382 continue; 383 384 return (xpio_attr_xlates[i].xt_xlate_tostr(val, 385 xpio_attr_xlates[i].xt_pairs, buf, buflen)); 386 } 387 388 return (false); 389 } 390 391 bool 392 xpio_gpio_attr_xlate_to_str(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr, 393 char *buf, size_t buflen) 394 { 395 uint32_t val; 396 397 if (!xpio_gpio_attr_value_uint32(attr, &val)) { 398 return (false); 399 } 400 401 return (xpio_gpio_attr_xlate_uint32_to_str(gi, attr, val, buf, buflen)); 402 } 403 404 xpio_gpio_attr_t * 405 xpio_gpio_attr_find(xpio_gpio_info_t *gi, const char *name) 406 { 407 nvpair_t *pair; 408 409 if (strcmp(name, KGPIO_ATTR_META) == 0) { 410 return (NULL); 411 } 412 413 if (nvlist_lookup_nvpair(gi->xgi_nvl, name, &pair) != 0) { 414 return (NULL); 415 } 416 417 switch (nvpair_type(pair)) { 418 case DATA_TYPE_UINT32: 419 case DATA_TYPE_STRING: 420 break; 421 default: 422 return (NULL); 423 } 424 425 return ((xpio_gpio_attr_t *)pair); 426 } 427 428 xpio_gpio_attr_t * 429 xpio_gpio_attr_next(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr) 430 { 431 nvpair_t *pair_in = (nvpair_t *)attr; 432 433 for (;;) { 434 nvpair_t *next = nvlist_next_nvpair(gi->xgi_nvl, pair_in); 435 if (next == NULL) { 436 return (NULL); 437 } 438 439 switch (nvpair_type(next)) { 440 case DATA_TYPE_UINT32: 441 case DATA_TYPE_STRING: 442 break; 443 default: 444 pair_in = next; 445 continue; 446 } 447 448 if (strcmp(KGPIO_ATTR_META, nvpair_name(next)) == 0) { 449 pair_in = next; 450 continue; 451 } 452 453 return ((xpio_gpio_attr_t *)next); 454 } 455 } 456 457 const char * 458 xpio_gpio_attr_name(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr) 459 { 460 nvpair_t *pair = (nvpair_t *)attr; 461 return (nvpair_name(pair)); 462 } 463 464 xpio_attr_type_t 465 xpio_gpio_attr_type(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr) 466 { 467 nvpair_t *pair = (nvpair_t *)attr; 468 469 /* 470 * We should only have handed out an nvpair that matches these two types 471 * at this point. 472 */ 473 switch (nvpair_type(pair)) { 474 case DATA_TYPE_UINT32: 475 return (XPIO_ATTR_TYPE_UINT32); 476 case DATA_TYPE_STRING: 477 return (XPIO_ATTR_TYPE_STRING); 478 default: 479 abort(); 480 } 481 } 482 483 static const char * 484 xpio_gpio_attr_type_name(xpio_attr_type_t type) 485 { 486 switch (type) { 487 case XPIO_ATTR_TYPE_UINT32: 488 return ("XPIO_ATTR_TYPE_UINT32"); 489 case XPIO_ATTR_TYPE_STRING: 490 return ("XPIO_ATTR_TYPE_STRING"); 491 default: 492 abort(); 493 } 494 } 495 496 bool 497 xpio_gpio_attr_value_string(xpio_gpio_attr_t *attr, const char **outp) 498 { 499 char *lookup; 500 501 if (nvpair_value_string((nvpair_t *)attr, &lookup) != 0) { 502 return (false); 503 } 504 505 *outp = lookup; 506 return (true); 507 } 508 509 bool 510 xpio_gpio_attr_value_uint32(xpio_gpio_attr_t *attr, uint32_t *outp) 511 { 512 return (nvpair_value_uint32((nvpair_t *)attr, outp) == 0); 513 } 514 515 void 516 xpio_gpio_attr_possible_string(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr, 517 const char ***outp, uint_t *countp) 518 { 519 nvlist_t *meta_nvl, *attr_nvl; 520 const char *key = nvpair_name((nvpair_t *)attr); 521 char **strp; 522 523 *outp = NULL; 524 *countp = 0; 525 526 if (nvlist_lookup_nvlist(gi->xgi_nvl, KGPIO_ATTR_META, &meta_nvl) != 527 0) { 528 return; 529 } 530 531 if (nvlist_lookup_nvlist(meta_nvl, key, &attr_nvl) != 0) { 532 return; 533 } 534 535 if (nvlist_lookup_string_array(attr_nvl, KGPIO_ATTR_POS, &strp, 536 countp) != 0) { 537 *outp = (const char **)strp; 538 } 539 } 540 541 void 542 xpio_gpio_attr_possible_uint32(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr, 543 uint32_t **outp, uint_t *countp) 544 { 545 nvlist_t *meta_nvl, *attr_nvl; 546 const char *key = nvpair_name((nvpair_t *)attr); 547 548 *outp = NULL; 549 *countp = 0; 550 551 if (nvlist_lookup_nvlist(gi->xgi_nvl, KGPIO_ATTR_META, &meta_nvl) != 552 0) { 553 return; 554 } 555 556 if (nvlist_lookup_nvlist(meta_nvl, key, &attr_nvl) != 0) { 557 return; 558 } 559 560 (void) nvlist_lookup_uint32_array(attr_nvl, KGPIO_ATTR_POS, outp, 561 countp); 562 } 563 564 xpio_attr_prot_t 565 xpio_gpio_attr_prot(xpio_gpio_info_t *gi, xpio_gpio_attr_t *attr) 566 { 567 uint32_t prot; 568 nvlist_t *meta_nvl, *attr_nvl; 569 const char *key = nvpair_name((nvpair_t *)attr); 570 571 if (nvlist_lookup_nvlist(gi->xgi_nvl, KGPIO_ATTR_META, &meta_nvl) != 572 0) { 573 return (XPIO_ATTR_PROT_RO); 574 } 575 576 if (nvlist_lookup_nvlist(meta_nvl, key, &attr_nvl) != 0) { 577 return (XPIO_ATTR_PROT_RO); 578 } 579 580 if (nvlist_lookup_uint32(attr_nvl, KGPIO_ATTR_PROT, &prot) != 0) { 581 return (XPIO_ATTR_PROT_RO); 582 } 583 584 switch (prot) { 585 case KGPIO_PROT_RW: 586 return (XPIO_ATTR_PROT_RW); 587 case KGPIO_PROT_RO: 588 default: 589 return (XPIO_ATTR_PROT_RO); 590 } 591 } 592 593 bool 594 xpio_gpio_attr_set_uint32(xpio_gpio_update_t *update, xpio_gpio_attr_t *attr, 595 uint32_t val) 596 { 597 int ret; 598 xpio_attr_type_t type = xpio_gpio_attr_type(update->xgo_gpio, attr); 599 const char *key = xpio_gpio_attr_name(update->xgo_gpio, attr); 600 601 if (type != XPIO_ATTR_TYPE_UINT32) { 602 return (xpio_update_error(update, XPIO_UPDATE_ERR_BAD_TYPE, 0, 603 "attribute type for %s is %s, not a uint32", key, 604 xpio_gpio_attr_type_name(type))); 605 } 606 607 ret = nvlist_add_uint32(update->xgo_update, key, val); 608 switch (ret) { 609 case 0: 610 return (xpio_update_success(update)); 611 case ENOMEM: 612 return (xpio_update_error(update, XPIO_UPDATE_ERR_NO_MEM, ret, 613 "failed to allocate memory to insert attribute %s into " 614 "update structure", key)); 615 default: 616 return (xpio_update_error(update, XPIO_UPDATE_ERR_INTERNAL, ret, 617 "unexpected internal error while trying to insert " 618 "attribute %s into update structure: %s", key, 619 strerror(ret))); 620 } 621 } 622 623 bool 624 xpio_gpio_attr_set_str(xpio_gpio_update_t *update, xpio_gpio_attr_t *attr, 625 const char *val) 626 { 627 int ret; 628 xpio_attr_type_t type = xpio_gpio_attr_type(update->xgo_gpio, attr); 629 const char *key = xpio_gpio_attr_name(update->xgo_gpio, attr); 630 631 if (type != XPIO_ATTR_TYPE_STRING) { 632 return (xpio_update_error(update, XPIO_UPDATE_ERR_BAD_TYPE, 0, 633 "attribute type for %s is %s, not a string", key, 634 xpio_gpio_attr_type_name(type))); 635 } 636 637 ret = nvlist_add_string(update->xgo_update, key, val); 638 switch (ret) { 639 case 0: 640 return (xpio_update_success(update)); 641 case ENOMEM: 642 return (xpio_update_error(update, XPIO_UPDATE_ERR_NO_MEM, ret, 643 "failed to allocate memory to insert attribute %s into " 644 "update structure", key)); 645 default: 646 return (xpio_update_error(update, XPIO_UPDATE_ERR_INTERNAL, ret, 647 "unexpected internal error while trying to insert " 648 "attribute %s into update structure: %s", key, 649 strerror(ret))); 650 } 651 } 652 653 /* 654 * This update path attempts to translate the passed in string into the 655 * appropriate attribute type. This is designed for tools that want to work in 656 * the more human values that we have for various GPIO attributes. 657 */ 658 bool 659 xpio_gpio_attr_from_str(xpio_gpio_update_t *update, xpio_gpio_attr_t *attr, 660 const char *raw_val) 661 { 662 xpio_attr_type_t type = xpio_gpio_attr_type(update->xgo_gpio, attr); 663 const char *key = xpio_gpio_attr_name(update->xgo_gpio, attr); 664 665 /* 666 * If the data type for this is a string, then we can just insert the 667 * value as is and there is no need for translation. Otherwise, we must 668 * look at the data type and perform the appropriate translation. 669 */ 670 if (type == XPIO_ATTR_TYPE_STRING) { 671 return (xpio_gpio_attr_set_str(update, attr, raw_val)); 672 } 673 674 for (size_t i = 0; i < ARRAY_SIZE(xpio_attr_xlates); i++) { 675 uint32_t u32; 676 677 if (strcmp(key, xpio_attr_xlates[i].xt_name) != 0) 678 continue; 679 if (!xpio_attr_xlates[i].xt_xlate_tou32(raw_val, 680 xpio_attr_xlates[i].xt_pairs, &u32)) { 681 return (xpio_update_error(update, 682 XPIO_UPDATE_ERR_CANT_XLATE, 0, "failed to " 683 "translate attribute %s value %s to a uint32", 684 key, raw_val)); 685 } 686 687 return (xpio_gpio_attr_set_uint32(update, attr, u32)); 688 } 689 690 return (xpio_update_error(update, XPIO_UPDATE_ERR_INTERNAL, ENOENT, 691 "missing internal translator for attr %s to type %s", key, 692 xpio_gpio_attr_type_name(type))); 693 694 } 695 696 xpio_gpio_attr_err_t * 697 xpio_gpio_attr_err_next(xpio_gpio_update_t *update, xpio_gpio_attr_err_t *cur) 698 { 699 nvpair_t *pair_in = (nvpair_t *)cur; 700 701 if (update->xgo_err_nvl == NULL) { 702 return (NULL); 703 } 704 705 for (;;) { 706 nvpair_t *next = nvlist_next_nvpair(update->xgo_err_nvl, 707 pair_in); 708 if (next == NULL) { 709 return (NULL); 710 } 711 712 if (nvpair_type(next) != DATA_TYPE_UINT32) { 713 pair_in = next; 714 continue; 715 } 716 717 return ((xpio_gpio_attr_err_t *)next); 718 } 719 } 720 721 const char * 722 xpio_gpio_attr_err_name(xpio_gpio_attr_err_t *err) 723 { 724 nvpair_t *pair = (nvpair_t *)err; 725 return (nvpair_name(pair)); 726 } 727 728 xpio_update_err_t 729 xpio_gpio_attr_err_err(xpio_gpio_attr_err_t *err) 730 { 731 uint32_t val; 732 nvpair_t *pair = (nvpair_t *)err; 733 734 if (nvpair_value_uint32(pair, &val) != 0) { 735 return (XPIO_UPDATE_ERR_INTERNAL); 736 } 737 738 switch (val) { 739 case KGPIO_ATTR_ERR_OK: 740 return (XPIO_UPDATE_ERR_OK); 741 case KGPIO_ATTR_ERR_ATTR_RO: 742 return (XPIO_UPDATE_ERR_RO); 743 case KGPIO_ATTR_ERR_UNKNOWN_ATTR: 744 return (XPIO_UPDATE_ERR_UNKNOWN_ATTR); 745 case KGPIO_ATTR_ERR_BAD_TYPE: 746 return (XPIO_UPDATE_ERR_BAD_TYPE); 747 case KGPIO_ATTR_ERR_UNKNOWN_VAL: 748 return (XPIO_UPDATE_ERR_CANT_XLATE); 749 case KGPIO_ATTR_ERR_CANT_APPLY_VAL: 750 return (XPIO_UPDATE_ERR_CANT_APPLY_VAL); 751 default: 752 return (XPIO_UPDATE_ERR_INTERNAL); 753 } 754 } 755