/* * In this comment typed properties are those of type DI_PROP_TYPE_UNDEF_IT, * DI_PROP_TYPE_BOOLEAN, DI_PROP_TYPE_INT, DI_PROP_TYPE_INT64, * DI_PROP_TYPE_BYTE, and DI_PROP_TYPE_STRING. * * The guessing algorithm is: * 1. If the property is typed and the type is consistent with the value of * the property, then the property is of that type. If the type is not * consistent with value of the property, then the type is treated as * alien to prtconf. * 2. If the property is of type DI_PROP_TYPE_UNKNOWN the following steps * are carried out. * a. If the value of the property is consistent with a string property, * the type of the property is DI_PROP_TYPE_STRING. * b. Otherwise, if the value of the property is consistent with an integer * property, the type of the property is DI_PROP_TYPE_INT. * c. Otherwise, the property type is treated as alien to prtconf. * 3. If the property type is alien to prtconf, then the property value is * read by the appropriate routine for untyped properties and the following * steps are carried out. * a. If the length that the property routine returned is zero, the * property is of type DI_PROP_TYPE_BOOLEAN. * b. Otherwise, if the length that the property routine returned is * positive, then the property value is treated as raw data of type * DI_PROP_TYPE_UNKNOWN. * c. Otherwise, if the length that the property routine returned is * negative, then there is some internal inconsistency and this is * treated as an error and no type is determined. * * * Joyent/jwilsdon: This function was taken and modified from: * * <illumos>/usr/src/cmd/prtconf/pdevinfo.c * */ static int prop_type_guess(di_prop_t prop, void **prop_data, int *prop_type) { int len, type; type = di_prop_type(prop); switch (type) { case DI_PROP_TYPE_UNDEF_IT: case DI_PROP_TYPE_BOOLEAN: *prop_data = NULL; *prop_type = type; return (0); case DI_PROP_TYPE_INT: len = di_prop_ints(prop, (int **)prop_data); break; case DI_PROP_TYPE_INT64: len = di_prop_int64(prop, (int64_t **)prop_data); break; case DI_PROP_TYPE_BYTE: len = di_prop_bytes(prop, (uchar_t **)prop_data); break; case DI_PROP_TYPE_STRING: len = di_prop_strings(prop, (char **)prop_data); break; case DI_PROP_TYPE_UNKNOWN: len = di_prop_strings(prop, (char **)prop_data); if ((len > 0) && ((*(char **)prop_data)[0] != 0)) { *prop_type = DI_PROP_TYPE_STRING; return (len); } len = di_prop_ints(prop, (int **)prop_data); type = DI_PROP_TYPE_INT; break; default: len = -1; } if (len > 0) { *prop_type = type; return (len); } len = di_prop_rawdata(prop, (uchar_t **)prop_data); if (len < 0) { return (-1); } else if (len == 0) { *prop_type = DI_PROP_TYPE_BOOLEAN; return (0); } *prop_type = DI_PROP_TYPE_UNKNOWN; return (len); }
/* * This function is called from di_walk_minor() when any PROBE is processed */ static int probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) { probe_info_t *pinfo = (probe_info_t *)arg; char *nexus_name, *nexus_dev_path; nexus_t *nexus; int fd; char nexus_path[MAXPATHLEN]; di_prop_t prop; char *strings; int *ints; int numval; int pci_node = 0; int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M); int domain = 0; #ifdef __sparc int bus_range_found = 0; int device_type_found = 0; di_prom_prop_t prom_prop; #endif #ifdef DEBUG nexus_name = di_devfs_minor_path(minor); fprintf(stderr, "-- device name: %s\n", nexus_name); #endif for (prop = di_prop_next(di_node, NULL); prop != NULL; prop = di_prop_next(di_node, prop)) { const char *prop_name = di_prop_name(prop); #ifdef DEBUG fprintf(stderr, " property: %s\n", prop_name); #endif if (strcmp(prop_name, "device_type") == 0) { numval = di_prop_strings(prop, &strings); if (numval == 1) { if (strncmp(strings, "pci", 3) != 0) /* not a PCI node, bail */ return (DI_WALK_CONTINUE); else { pci_node = 1; #ifdef __sparc device_type_found = 1; #endif } } } else if (strcmp(prop_name, "class-code") == 0) { /* not a root bus node, bail */ return (DI_WALK_CONTINUE); } else if (strcmp(prop_name, "bus-range") == 0) { numval = di_prop_ints(prop, &ints); if (numval == 2) { first_bus = ints[0]; last_bus = ints[1]; #ifdef __sparc bus_range_found = 1; #endif } } else if (strcmp(prop_name, "pciseg") == 0) { numval = di_prop_ints(prop, &ints); if (numval == 1) { domain = ints[0]; } } } #ifdef __sparc if ((!device_type_found) && di_phdl) { numval = di_prom_prop_lookup_strings(di_phdl, di_node, "device_type", &strings); if (numval == 1) { if (strncmp(strings, "pci", 3) != 0) return (DI_WALK_CONTINUE); else pci_node = 1; } } if ((!bus_range_found) && di_phdl) { numval = di_prom_prop_lookup_ints(di_phdl, di_node, "bus-range", &ints); if (numval == 2) { first_bus = ints[0]; last_bus = ints[1]; } } #endif if (pci_node != 1) return (DI_WALK_CONTINUE); /* we have a PCI root bus node. */ nexus = calloc(1, sizeof(nexus_t)); if (nexus == NULL) { (void) fprintf(stderr, "Error allocating memory for nexus: %s\n", strerror(errno)); return (DI_WALK_TERMINATE); } nexus->first_bus = first_bus; nexus->last_bus = last_bus; nexus->domain = domain; #ifdef __sparc if ((nexus->devlist = calloc(INITIAL_NUM_DEVICES, sizeof (struct pci_device *))) == NULL) { (void) fprintf(stderr, "Error allocating memory for nexus devlist: %s\n", strerror(errno)); free (nexus); return (DI_WALK_TERMINATE); } nexus->num_allocated_elems = INITIAL_NUM_DEVICES; nexus->num_devices = 0; #endif nexus_name = di_devfs_minor_path(minor); if (nexus_name == NULL) { (void) fprintf(stderr, "Error getting nexus path: %s\n", strerror(errno)); free(nexus); return (DI_WALK_CONTINUE); } snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name); di_devfs_path_free(nexus_name); #ifdef DEBUG fprintf(stderr, "nexus = %s, bus-range = %d - %d\n", nexus_path, first_bus, last_bus); #endif if ((fd = open(nexus_path, O_RDWR | O_CLOEXEC)) >= 0) { nexus->fd = fd; nexus->path = strdup(nexus_path); nexus_dev_path = di_devfs_path(di_node); nexus->dev_path = strdup(nexus_dev_path); di_devfs_path_free(nexus_dev_path); if ((do_probe(nexus, pinfo) != 0) && (errno != ENXIO)) { (void) fprintf(stderr, "Error probing node %s: %s\n", nexus_path, strerror(errno)); (void) close(fd); free(nexus->path); free(nexus->dev_path); free(nexus); } else { nexus->next = nexus_list; nexus_list = nexus; } } else { (void) fprintf(stderr, "Error opening %s: %s\n", nexus_path, strerror(errno)); free(nexus); } return DI_WALK_CONTINUE; }
/* * This function is called from di_walk_minor() when any PROBE is processed */ static int probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) { probe_info_t *pinfo = (probe_info_t *)arg; char *nexus_name, *nexus_dev_path; nexus_t *nexus; int fd; char nexus_path[MAXPATHLEN]; di_prop_t prop; char *strings; int *ints; int numval; int pci_node = 0; int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M); int domain = 0; di_node_t rnode = DI_NODE_NIL; #ifdef __sparc int bus_range_found = 0; int device_type_found = 0; di_prom_prop_t prom_prop; #endif #ifdef DEBUG nexus_name = di_devfs_minor_path(minor); fprintf(stderr, "-- device name: %s\n", nexus_name); di_devfs_path_free(nexus_name); #endif for (prop = di_prop_next(di_node, NULL); prop != NULL; prop = di_prop_next(di_node, prop)) { const char *prop_name = di_prop_name(prop); #ifdef DEBUG fprintf(stderr, " property: %s\n", prop_name); #endif if (strcmp(prop_name, "device_type") == 0) { numval = di_prop_strings(prop, &strings); if (numval == 1) { if (strncmp(strings, "pci", 3) != 0) /* not a PCI node, bail */ return (DI_WALK_CONTINUE); else { pci_node = 1; #ifdef __sparc device_type_found = 1; #endif } } } else if (strcmp(prop_name, "class-code") == 0) { /* not a root bus node, bail */ return (DI_WALK_CONTINUE); } else if (strcmp(prop_name, "bus-range") == 0) { numval = di_prop_ints(prop, &ints); if (numval == 2) { first_bus = ints[0]; last_bus = ints[1]; #ifdef __sparc bus_range_found = 1; #endif } } #ifdef __sparc domain = nexus_count; #else else if (strcmp(prop_name, "pciseg") == 0) { numval = di_prop_ints(prop, &ints); if (numval == 1) { domain = ints[0]; } } #endif }
/* * This function is identical to the one in the picldevtree plugin. * Unfortunately we can't just reuse that code. */ static void add_devinfo_props(picl_nodehdl_t nodeh, di_node_t di_node) { int instance; char *di_val; di_prop_t di_prop; int di_ptype; ptree_propinfo_t propinfo; instance = di_instance(di_node); (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_INT, PICL_READ, sizeof (instance), PICL_PROP_INSTANCE, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, NULL); di_val = di_bus_addr(di_node); if (di_val) { (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, PICL_PROP_BUS_ADDR, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, NULL); } di_val = di_binding_name(di_node); if (di_val) { (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, PICL_PROP_BINDING_NAME, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, NULL); } di_val = di_driver_name(di_node); if (di_val) { (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, PICL_PROP_DRIVER_NAME, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, NULL); } di_val = di_devfs_path(di_node); if (di_val) { (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, PICL_PROP_DEVFS_PATH, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, NULL); di_devfs_path_free(di_val); } for (di_prop = di_prop_next(di_node, DI_PROP_NIL); di_prop != DI_PROP_NIL; di_prop = di_prop_next(di_node, di_prop)) { di_val = di_prop_name(di_prop); di_ptype = di_prop_type(di_prop); switch (di_ptype) { case DI_PROP_TYPE_BOOLEAN: (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID, PICL_READ, (size_t)0, di_val, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL); break; case DI_PROP_TYPE_INT: { int *idata; int len; len = di_prop_ints(di_prop, &idata); if (len < 0) /* Recieved error, so ignore prop */ break; if (len == 1) (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_INT, PICL_READ, len * sizeof (int), di_val, NULL, NULL); else (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_BYTEARRAY, PICL_READ, len * sizeof (int), di_val, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, idata, NULL); } break; case DI_PROP_TYPE_STRING: { char *sdata; int len; len = di_prop_strings(di_prop, &sdata); if (len < 0) break; if (len == 1) { (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(sdata) + 1, di_val, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, sdata, NULL); } else { (void) add_string_list_prop(nodeh, di_val, sdata, len); } } break; case DI_PROP_TYPE_BYTE: { int len; unsigned char *bdata; len = di_prop_bytes(di_prop, &bdata); if (len < 0) break; (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_BYTEARRAY, PICL_READ, len, di_val, NULL, NULL); (void) ptree_create_and_add_prop(nodeh, &propinfo, bdata, NULL); } break; case DI_PROP_TYPE_UNKNOWN: break; case DI_PROP_TYPE_UNDEF_IT: break; default: break; } } }