Index: arch/sparc/sparc/promlib.c =================================================================== RCS file: /cvsroot/src/sys/arch/sparc/sparc/promlib.c,v retrieving revision 1.48 diff -u -p -r1.48 promlib.c --- arch/sparc/sparc/promlib.c 10 May 2021 13:59:30 -0000 1.48 +++ arch/sparc/sparc/promlib.c 15 Aug 2021 18:21:41 -0000 @@ -278,6 +278,85 @@ obp_device_enumerate_children(device_t d } OBP_DEVICE_CALL_REGISTER("device-enumerate-children", obp_device_enumerate_children) + +static int +obp_device_get_property(device_t dev, devhandle_t call_handle, void *v) +{ + struct device_get_property_args *args = v; + int node = devhandle_to_obp(call_handle); + int propsize, rv = -1; + + propsize = prom_getproplen(node, args->prop); + if (propsize < 0) { + return ENOENT; + } + + if (args->buf == NULL) { + goto done; + } + KASSERT(args->buflen != 0); + + /* Sizes must fit in int. */ + if (args->buflen > INT_MAX) { + args->buflen = INT_MAX; + } + + switch (args->reqtype) { + case PROP_TYPE_NUMBER: + if ((propsize == sizeof(uint32_t) || + propsize == sizeof(uint64_t)) && + args->buflen == propsize) { + rv = _prom_getprop(node, args->prop, args->buf, + (int)args->buflen); + } else if (propsize == sizeof(uint32_t) && + args->buflen == sizeof(uint64_t)) { + uint32_t val32; + rv = _prom_getprop(node, args->prop, &val32, + sizeof(val32)); + if (rv == sizeof(uint32_t)) { + *(uint64_t *)args->buf = val32; + } + } else { + /* Looks like the wrong type. */ + return EFTYPE; + } + break; + + case PROP_TYPE_STRING: + case PROP_TYPE_DATA: + rv = _prom_getprop(node, args->prop, args->buf, + (int)args->buflen); + if (args->reqtype == PROP_TYPE_STRING) { + char *cp = args->buf; + if (rv > (int)args->buflen) { + cp[args->buflen - 1] = '\0'; + } else { + cp[rv > 0 ? (rv - 1) : 0] = '\0'; + } + } + break; + + case PROP_TYPE_BOOL: + /* Property is present -> true */ + *(bool *)args->buf = true; + break; + + default: + return EFTYPE; + } + + if (rv != propsize) { + /* Something has gone off the rails. */ + return EIO; + } + + done: + args->propsize = propsize; + args->encoding = _BYTE_ORDER; /* i.e. _BIG_ENDIAN */ + args->type = PROP_TYPE_UNKNOWN; + return 0; +} +OBP_DEVICE_CALL_REGISTER("device-get-property", obp_device_get_property) #endif /* ! _STANDALONE */ /* Index: dev/acpi/acpi_util.c =================================================================== RCS file: /cvsroot/src/sys/dev/acpi/acpi_util.c,v retrieving revision 1.25 diff -u -p -r1.25 acpi_util.c --- dev/acpi/acpi_util.c 9 Aug 2021 20:49:09 -0000 1.25 +++ dev/acpi/acpi_util.c 15 Aug 2021 18:21:41 -0000 @@ -895,7 +895,7 @@ acpi_dsd_property(ACPI_HANDLE handle, co if (strcmp(propkey->String.Pointer, prop) != 0) continue; - if (propval->Type != type) { + if (type != ACPI_TYPE_ANY && propval->Type != type) { return AE_TYPE; } else { *ret = propval; @@ -945,6 +945,152 @@ acpi_dsd_string(ACPI_HANDLE handle, cons return rv; } +static bool +prop_type_to_acpi(prop_type_t type, ACPI_OBJECT_TYPE *out) +{ + switch (type) { + case PROP_TYPE_NUMBER: + case PROP_TYPE_BOOL: + *out = ACPI_TYPE_INTEGER; + break; + + case PROP_TYPE_DATA: + *out = ACPI_TYPE_BUFFER; + break; + + case PROP_TYPE_STRING: + *out = ACPI_TYPE_STRING; + break; + + case PROP_TYPE_UNKNOWN: + *out = ACPI_TYPE_ANY; + break; + + default: + return false; + } + + return true; +} + +static bool +acpi_type_to_prop(ACPI_OBJECT_TYPE acpitype, prop_type_t *out) +{ + switch (acpitype) { + case ACPI_TYPE_INTEGER: + *out = PROP_TYPE_NUMBER; + break; + + case ACPI_TYPE_BUFFER: + *out = PROP_TYPE_DATA; + break; + + case PROP_TYPE_STRING: + *out = PROP_TYPE_STRING; + break; + + default: + return false; + } + + return true; +} + +static int +acpi_device_get_property(device_t dev, devhandle_t call_handle, void *v) +{ + struct device_get_property_args *args = v; + ACPI_HANDLE hdl = devhandle_to_acpi(call_handle); + ACPI_OBJECT *propval; + ACPI_OBJECT_TYPE acpitype; + ACPI_STATUS rv; + ACPI_BUFFER buf; + int error = 0; + size_t copysize; + + /* + * No need to clamp size; ACPI sizes are unsigned (UINT32), + * and the upper layer has already clamped to fit in ssize_t. + */ + + if (! prop_type_to_acpi(args->reqtype, &acpitype)) { + return EFTYPE; + } + + buf.Pointer = NULL; + buf.Length = ACPI_ALLOCATE_BUFFER; + + rv = acpi_dsd_property(hdl, args->prop, &buf, acpitype, &propval); + if (!ACPI_SUCCESS(rv)) { + error = rv == AE_TYPE ? EFTYPE : ENOENT; + goto out; + } + + args->encoding = _BYTE_ORDER; + if (! acpi_type_to_prop(propval->Type, &args->type)) { + error = EFTYPE; + goto out; + } + + switch (propval->Type) { + case ACPI_TYPE_INTEGER: + args->propsize = sizeof(propval->Integer.Value); + if (args->buf != NULL) { + if (args->reqtype == PROP_TYPE_BOOL) { + *(bool *)args->buf = + propval->Integer.Value != 0; + goto out; + } + KASSERT(args->reqtype == PROP_TYPE_NUMBER); + if (args->buflen == sizeof(uint32_t)) { + if (propval->Integer.Value > UINT32_MAX) { + error = ERANGE; + goto out; + } + *(uint32_t *)args->buf = + (uint32_t)propval->Integer.Value; + } else if (args->buflen == sizeof(uint64_t)) { + *(uint64_t *)args->buf = propval->Integer.Value; + } else { + error = EFTYPE; /* wut? */ + } + } + break; + + case ACPI_TYPE_STRING: + /* +1 for trailing NUL */ + args->propsize = propval->String.Length + 1; + if (args->buf != NULL) { + KASSERT(args->reqtype == PROP_TYPE_STRING); + strlcpy(args->buf, propval->String.Pointer, + args->buflen); + } + break; + + case ACPI_TYPE_BUFFER: + copysize = args->propsize = propval->Buffer.Length; + if (args->buf != NULL) { + KASSERT(args->reqtype == PROP_TYPE_DATA); + if (args->buflen < copysize) { + copysize = args->buflen; + } + memcpy(args->buf, propval->Buffer.Pointer, copysize); + } + break; + + default: + error = EFTYPE; + goto out; + } + + out: + if (buf.Pointer != NULL) { + ACPI_FREE(buf.Pointer); + } + return error; +} +ACPI_DEVICE_CALL_REGISTER("device-get-property", acpi_device_get_property) + /* * Device Specific Method (_DSM) support */ Index: dev/ofw/ofw_subr.c =================================================================== RCS file: /cvsroot/src/sys/dev/ofw/ofw_subr.c,v retrieving revision 1.58 diff -u -p -r1.58 ofw_subr.c --- dev/ofw/ofw_subr.c 24 Apr 2021 23:36:57 -0000 1.58 +++ dev/ofw/ofw_subr.c 15 Aug 2021 18:21:41 -0000 @@ -133,6 +133,89 @@ of_device_enumerate_children(device_t de OF_DEVICE_CALL_REGISTER("device-enumerate-children", of_device_enumerate_children) +static int +of_device_get_property(device_t dev, devhandle_t call_handle, void *v) +{ + struct device_get_property_args *args = v; + int phandle = devhandle_to_of(call_handle); + int propsize, rv = -1; + + propsize = OF_getproplen(phandle, args->prop); + if (propsize < 0) { + return ENOENT; + } + + if (args->buf == NULL) { + goto done; + } + KASSERT(args->buflen != 0); + + /* Sizes must fit in int. */ + if (args->buflen > INT_MAX) { + args->buflen = INT_MAX; + } + + switch (args->reqtype) { + case PROP_TYPE_NUMBER: + if (propsize == sizeof(uint32_t) && args->buflen == propsize) { + rv = of_getprop_uint32(phandle, args->prop, args->buf); + } else if (propsize == sizeof(uint64_t) && + args->buflen == propsize) { + rv = of_getprop_uint64(phandle, args->prop, args->buf); + } else if (propsize == sizeof(uint32_t) && + args->buflen == sizeof(uint64_t)) { + uint32_t val32; + rv = of_getprop_uint32(phandle, args->prop, &val32); + if (rv == 0) { + *(uint64_t *)args->buf = val32; + } + } else { + /* Looks like the wrong type. */ + return EFTYPE; + } + if (rv == 0) { + /* of_getprop_uintNN() returns 0, not prop length. */ + rv = propsize; + } + break; + + case PROP_TYPE_STRING: + case PROP_TYPE_DATA: + rv = OF_getprop(phandle, args->prop, args->buf, + (int)args->buflen); + if (args->reqtype == PROP_TYPE_STRING) { + char *cp = args->buf; + if (rv > args->buflen) { + cp[args->buflen - 1] = '\0'; + } else { + cp[rv > 0 ? (rv - 1) : 0] = '\0'; + } + } + break; + + case PROP_TYPE_BOOL: + /* Property is present -> true */ + *(bool *)args->buf = true; + rv = propsize; + break; + + default: + return EFTYPE; + } + + if (rv != propsize) { + /* Something has gone off the rails. */ + return EIO; + } + + done: + args->propsize = propsize; + args->encoding = _BIG_ENDIAN; + args->type = PROP_TYPE_UNKNOWN; + return 0; +} +OF_DEVICE_CALL_REGISTER("device-get-property", of_device_get_property) + /* * int of_decode_int(p) * Index: kern/subr_device.c =================================================================== RCS file: /cvsroot/src/sys/kern/subr_device.c,v retrieving revision 1.8 diff -u -p -r1.8 subr_device.c --- kern/subr_device.c 7 Aug 2021 18:16:42 -0000 1.8 +++ kern/subr_device.c 15 Aug 2021 18:21:42 -0000 @@ -284,10 +284,9 @@ device_handle(device_t dev) return dev->dv_handle; } -int -device_call(device_t dev, const char *name, void *arg) +static int +_device_call(device_t dev, devhandle_t handle, const char *name, void *arg) { - devhandle_t handle = device_handle(dev); device_call_t call; devhandle_t call_handle; @@ -299,6 +298,12 @@ device_call(device_t dev, const char *na } int +device_call(device_t dev, const char *name, void *arg) +{ + return _device_call(dev, dev->dv_handle, name, arg); +} + +int device_enumerate_children(device_t dev, bool (*callback)(device_t, devhandle_t, void *), void *callback_arg) @@ -310,3 +315,525 @@ device_enumerate_children(device_t dev, return device_call(dev, "device-enumerate-children", &args); } + +static int +device_getprop_dict(device_t dev, struct device_get_property_args *args) +{ + prop_dictionary_t dict = dev->dv_properties; + prop_object_t propval; + size_t copysize; + + /* + * Return ENOENT before any other error so that we can rely + * on that error to tell us "property does not exist in this + * layer, so go check the platform device tree". + */ + propval = prop_dictionary_get(dict, args->prop); + if (propval == NULL) { + return ENOENT; + } + if (args->reqtype != PROP_TYPE_UNKNOWN && + args->reqtype != prop_object_type(propval)) { + return EFTYPE; + } + + args->encoding = _BYTE_ORDER; + args->type = prop_object_type(propval); + + switch (args->type) { + case PROP_TYPE_NUMBER: + args->propsize = sizeof(uintmax_t); + if (args->buf != NULL) { + if (args->buflen == sizeof(uint32_t)) { + if (!prop_number_uint32_value(propval, + args->buf)) { + return ERANGE; + } + } else if (args->buflen == sizeof(uint64_t)) { + if (!prop_number_uint64_value(propval, + args->buf)) { + return ERANGE; + } + } else { + return EFTYPE; /* wut? */ + } + } + break; + + case PROP_TYPE_STRING: + /* +1 for trailing NUL */ + args->propsize = prop_string_size(propval) + 1; + if (args->buf != NULL) { + strlcpy(args->buf, prop_string_value(propval), + args->buflen); + } + break; + + case PROP_TYPE_DATA: + copysize = args->propsize = prop_data_size(propval); + if (args->buf != NULL) { + if (args->buflen < copysize) { + copysize = args->buflen; + } + memcpy(args->buf, prop_data_value(propval), copysize); + } + break; + + case PROP_TYPE_BOOL: + args->propsize = sizeof(bool); + if (args->buf != NULL) { + *(bool *)args->buf = prop_bool_value(propval); + } + break; + + default: + return EFTYPE; + } + + return 0; +} + +static int +device_getprop_internal(device_t dev, devhandle_t handle, + struct device_get_property_args *args) +{ + int error; + + if (args->buf == NULL || args->buflen == 0) { + args->buf = NULL; + args->buflen = 0; + } else if (args->buflen > SSIZE_MAX) { + /* Sizes must fit in ssize_t. */ + args->buflen = SSIZE_MAX; + } + + /* Check the device's property dictionary first. */ + if (dev != NULL) { + error = device_getprop_dict(dev, args); + if (error != ENOENT) { + KASSERT(error != 0 || + (args->encoding == _BIG_ENDIAN || + args->encoding == _LITTLE_ENDIAN)); + return error; + } + } + + error = _device_call(dev, handle, "device-get-property", args); + KASSERT(error != 0 || + (args->encoding == _BIG_ENDIAN || + args->encoding == _LITTLE_ENDIAN)); + return error; +} + +/* + * device_getprop_size: + * devhandle_getprop_size: + * + * Returns the size of the specified property, or -1 if the + * property does not exist. + */ +static ssize_t +_device_getprop_size(device_t dev, devhandle_t handle, const char *prop) +{ + struct device_get_property_args args = { + .prop = prop, + .reqtype = PROP_TYPE_UNKNOWN, + }; + int error; + + error = device_getprop_internal(dev, handle, &args); + if (error) { + return -1; + } + + return args.propsize; +} + +ssize_t +device_getprop_size(device_t dev, const char *prop) +{ + return _device_getprop_size(dev, dev->dv_handle, prop); +} + +ssize_t +devhandle_getprop_size(devhandle_t handle, const char *prop) +{ + return _device_getprop_size(NULL, handle, prop); +} + +/* + * device_hasprop: + * devhandle_hasprop: + * + * Returns true if the device has the specified property. + */ +bool +device_hasprop(device_t dev, const char *prop) +{ + return device_getprop_size(dev, prop) >= 0; +} + +bool +devhandle_hasprop(devhandle_t handle, const char *prop) +{ + return devhandle_getprop_size(handle, prop) >= 0; +} + +/* + * device_getprop_encoding: + * devhandle_getprop_encoding: + * + * Returns the byte order encoding of the specified propery. + * N.B. The encoding is determined by the property's backing + * store, not by the property itself. + * + * Returns a byte order indicator (_BIG_ENDIAN, _LITTLE_ENDIAN) + * or -1 if the property does not exist. + */ +static int +_device_getprop_encoding(device_t dev, devhandle_t handle, const char *prop) +{ + struct device_get_property_args args = { + .prop = prop, + .reqtype = PROP_TYPE_UNKNOWN, + }; + int error; + + error = device_getprop_internal(dev, dev->dv_handle, &args); + if (error) { + return -1; + } + + return args.encoding; +} + +int +device_getprop_encoding(device_t dev, const char *prop) +{ + return _device_getprop_encoding(dev, dev->dv_handle, prop); +} + +int +devhandle_getprop_encoding(devhandle_t handle, const char *prop) +{ + return _device_getprop_encoding(NULL, handle, prop); +} + +/* + * device_getprop_type: + * devhandle_getprop_type: + * + * Returns the type of the specified property, constrained by + * the capabilities of the property's backing store. If the + * type cannot be determined, PROP_TYPE_UNKNOWN is returned. + * Note that some types may be aliased (e.g. a boolean property + * may be returned as PROP_TYPE_NUMBER if the backing store + * supports a number type but not a boolean type). + */ +static prop_type_t +_device_getprop_type(device_t dev, devhandle_t handle, const char *prop) +{ + struct device_get_property_args args = { + .prop = prop, + .reqtype = PROP_TYPE_UNKNOWN, + }; + int error; + + error = device_getprop_internal(dev, dev->dv_handle, &args); + if (error) { + return PROP_TYPE_UNKNOWN; + } + + return args.type; +} + +prop_type_t +device_getprop_type(device_t dev, const char *prop) +{ + return _device_getprop_type(dev, dev->dv_handle, prop); +} + +prop_type_t +devhandle_getprop_type(devhandle_t handle, const char *prop) +{ + return _device_getprop_type(NULL, handle, prop); +} + +/* + * device_getprop_data: + * devhandle_getprop_data: + * + * Return the specified property as an octet stream into + * the provided buffer, copying at most 'buflen' bytes. + * Returns -1 on error or the actual property size on success. + */ +static ssize_t +_device_getprop_data(device_t dev, devhandle_t handle, const char *prop, + void *buf, size_t buflen) +{ + struct device_get_property_args args = { + .prop = prop, + .buf = buf, + .buflen = buflen, + .reqtype = PROP_TYPE_DATA, + }; + int error; + + if (buf == NULL || buflen == 0) { + return -1; + } + + error = device_getprop_internal(dev, handle, &args); + if (error) { + return -1; + } + + return args.propsize; +} + +ssize_t +device_getprop_data(device_t dev, const char *prop, void *buf, size_t buflen) +{ + return _device_getprop_data(dev, dev->dv_handle, prop, buf, buflen); +} + +ssize_t +devhandle_getprop_data(devhandle_t handle, const char *prop, void *buf, + size_t buflen) +{ + return _device_getprop_data(NULL, handle, prop, buf, buflen); +} + +/* + * device_getprop_string: + * devhandle_getprop_string: + * + * Return the specified property as a NUL-terminated string + * into the provided buffer, copying at most 'buflen' bytes + * (including the terminating NUL). The returned string is + * always NUL-terminated. Returns -1 on error or the actual + * property size on success. + */ +static ssize_t +_device_getprop_string(device_t dev, devhandle_t handle, const char *prop, + char *buf, size_t buflen) +{ + struct device_get_property_args args = { + .prop = prop, + .buf = buf, + .buflen = buflen, + .reqtype = PROP_TYPE_STRING, + }; + int error; + + if (buf == NULL || buflen == 0) { + return -1; + } + + error = device_getprop_internal(dev, handle, &args); + if (error) { + return -1; + } + + return args.propsize; +} + +ssize_t +device_getprop_string(device_t dev, const char *prop, char *buf, size_t buflen) +{ + return _device_getprop_string(dev, dev->dv_handle, prop, buf, + buflen); +} + +ssize_t +devhandle_getprop_string(devhandle_t handle, const char *prop, char *buf, + size_t buflen) +{ + return _device_getprop_string(NULL, handle, prop, buf, buflen); +} + +/* + * device_getprop_bool: + * devhandle_getprop_bool: + * + * Get the specified property as a boolean value. Returns the value + * of the property, or false if the property does not exist. + */ +static bool +_device_getprop_bool(device_t dev, devhandle_t handle, const char *prop) +{ + bool val; + struct device_get_property_args args = { + .prop = prop, + .buf = &val, + .buflen = sizeof(val), + .reqtype = PROP_TYPE_BOOL, + }; + int error; + + error = device_getprop_internal(dev, dev->dv_handle, &args); + if (error) { + /* + * If the property exists but is not a boolean type + * (EFTYPE), we map this to 'true'; this is the same + * behavior that the traditional OpenBoot, OpenFirmware, + * and FDT interfaces have. + * + * If the property does not exist (ENOENT), or there + * is some other problem we translate this to 'false'. + */ + return error == EFTYPE ? true : false; + } + return val; +} + +bool +device_getprop_bool(device_t dev, const char *prop) +{ + return _device_getprop_bool(dev, dev->dv_handle, prop); +} + +bool +devhandle_getprop_bool(devhandle_t handle, const char *prop) +{ + return _device_getprop_bool(NULL, handle, prop); +} + +/* + * device_getprop_uint32: + * devhandle_getprop_uint32: + * + * Get the specified property as an unsigned 32-bit integer. + * Returns 0 upon success or -1 upon failure. + */ +static int +_device_getprop_uint32(device_t dev, devhandle_t handle, const char *prop, + uint32_t *valp) +{ + struct device_get_property_args args = { + .prop = prop, + .buf = valp, + .buflen = sizeof(*valp), + .reqtype = PROP_TYPE_NUMBER, + }; + int error; + + error = device_getprop_internal(dev, dev->dv_handle, &args); + if (error) { + return -1; + } + + return 0; +} + +int +device_getprop_uint32(device_t dev, const char *prop, uint32_t *valp) +{ + return _device_getprop_uint32(dev, dev->dv_handle, prop, valp); +} + +int +devhandle_getprop_uint32(devhandle_t handle, const char *prop, uint32_t *valp) +{ + return _device_getprop_uint32(NULL, handle, prop, valp); +} + +/* + * device_getprop_uint64: + * devhandle_getprop_uint64: + * + * Get the specified property as an unsigned 64-bit integer. + * Returns 0 upon success or -1 upon failure. + */ +static int +_device_getprop_uint64(device_t dev, devhandle_t handle, const char *prop, + uint64_t *valp) +{ + struct device_get_property_args args = { + .prop = prop, + .buf = valp, + .buflen = sizeof(*valp), + .reqtype = PROP_TYPE_NUMBER, + }; + int error; + + error = device_getprop_internal(dev, handle, &args); + if (error != 0) { + return -1; + } + + return 0; +} + +int +device_getprop_uint64(device_t dev, const char *prop, uint64_t *valp) +{ + return _device_getprop_uint64(dev, dev->dv_handle, prop, valp); +} + +int +devhandle_getprop_uint64(devhandle_t handle, const char *prop, uint64_t *valp) +{ + return _device_getprop_uint64(NULL, handle, prop, valp); +} + +/* + * device_setprop_data: + * + * Set the specified binary data property. + */ +int +device_setprop_data(device_t dev, const char *prop, const void *buf, size_t len) +{ + return prop_dictionary_set_data(dev->dv_properties, prop, buf, len) + ? 0 : -1; +} + +/* + * device_setprop_string: + * + * Set the specified string property. + */ +int +device_setprop_string(device_t dev, const char *prop, const char *str) +{ + return prop_dictionary_set_string(dev->dv_properties, prop, str) + ? 0 : -1; +} + +/* + * device_setprop_uint32: + * + * Set the specifed unsigned 32-bit integer property. + */ +int +device_setprop_uint32(device_t dev, const char *prop, uint32_t val) +{ + return prop_dictionary_set_uint32(dev->dv_properties, prop, val) + ? 0 : -1; +} + +/* + * device_setprop_uint64: + * + * Set the specified unsigned 64-bit integer property. + */ +int +device_setprop_uint64(device_t dev, const char *prop, uint64_t val) +{ + return prop_dictionary_set_uint64(dev->dv_properties, prop, val) + ? 0 : -1; +} + +/* + * device_delprop: + * + * Delete the spefified property. N.B. only deletes properties + * from the device's property dictionary; does not attempt to + * delete properties from the platform device tree. + */ +void +device_delprop(device_t dev, const char *prop) +{ + prop_dictionary_remove(dev->dv_properties, prop); +} Index: sys/device.h =================================================================== RCS file: /cvsroot/src/sys/sys/device.h,v retrieving revision 1.173 diff -u -p -r1.173 device.h --- sys/device.h 7 Aug 2021 18:16:42 -0000 1.173 +++ sys/device.h 15 Aug 2021 18:21:43 -0000 @@ -696,6 +696,39 @@ device_t device_find_by_driver_unit(cons int device_enumerate_children(device_t, bool (*)(device_t, devhandle_t, void *), void *); +bool device_hasprop(device_t, const char *); +ssize_t device_getprop_size(device_t, const char *); +int device_getprop_encoding(device_t, const char *); +prop_type_t device_getprop_type(device_t, const char *); + +ssize_t device_getprop_data(device_t, const char *, void *, size_t); +ssize_t device_getprop_string(device_t, const char *, char *, size_t); +bool device_getprop_bool(device_t, const char *); +int device_getprop_uint32(device_t, const char *, uint32_t *); +int device_getprop_uint64(device_t, const char *, uint64_t *); + +int device_setprop_data(device_t, const char *, const void *, + size_t); +int device_setprop_string(device_t, const char *, const char *); +int device_setprop_bool(device_t, const char *, bool); +int device_setprop_uint32(device_t, const char *, uint32_t); +int device_setprop_uint64(device_t, const char *, uint64_t); + +void device_delprop(device_t, const char *); + +bool devhandle_hasprop(devhandle_t, const char *); +ssize_t devhandle_getprop_size(devhandle_t, const char *); +int devhandle_getprop_encoding(devhandle_t, const char *); +prop_type_t devhandle_getprop_type(devhandle_t, const char *); + +ssize_t devhandle_getprop_data(devhandle_t, const char *, void *, + size_t); +ssize_t devhandle_getprop_string(devhandle_t, const char *, char *, + size_t); +bool devhandle_getprop_bool(devhandle_t, const char *); +int devhandle_getprop_uint32(devhandle_t, const char *, uint32_t *); +int devhandle_getprop_uint64(devhandle_t, const char *, uint64_t *); + int device_compatible_match(const char **, int, const struct device_compatible_entry *); int device_compatible_pmatch(const char **, int, @@ -794,6 +827,26 @@ device_t shutdown_next(struct shutdown_s * corresponding to the child device, as well as a user-supplied * argument. If the callback returns true, then enumeration * continues. If the callback returns false, enumeration is stopped. + * + * device-get-property + * + * Gets the specified propery (and its attributes) and copies it into + * the caller-provided buffer, up to the size specified by the caller. + * If the requested property type is PROP_TYPE_NUMBER, the value will + * be converted from the backing store's byte order to native byte order + * as needed. If no buffer is provided, only the property's attributes + * are returned. "dev" argument may be NULL. + * + * Errors: + * ENOENT The property does not exist. + * ERANGE The value stored in the property is out of + * range for the requested size. + * EFTYPE The property is a different type than what + * was requested. + * EINVAL The arguments provided to the call are + * invalid. + * EIO An input/output error to the backing + * store occurred. */ struct device_enumerate_children_args { @@ -801,6 +854,16 @@ struct device_enumerate_children_args { void * callback_arg; }; +struct device_get_property_args { + const char * prop; /* input */ + void * buf; /* input */ + size_t buflen; /* input */ + prop_type_t reqtype; /* input */ + ssize_t propsize; /* output */ + int encoding; /* output */ + prop_type_t type; /* output */ +}; + int device_call(device_t, const char *, void *); #endif /* _KERNEL */