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