int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
			      enum dev_prop_type proptype, void *val)
{
	const union acpi_object *obj;
	int ret;

	if (!val)
		return -EINVAL;

	if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
		ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
		if (ret)
			return ret;

		switch (proptype) {
		case DEV_PROP_U8:
			if (obj->integer.value > U8_MAX)
				return -EOVERFLOW;
			*(u8 *)val = obj->integer.value;
			break;
		case DEV_PROP_U16:
			if (obj->integer.value > U16_MAX)
				return -EOVERFLOW;
			*(u16 *)val = obj->integer.value;
			break;
		case DEV_PROP_U32:
			if (obj->integer.value > U32_MAX)
				return -EOVERFLOW;
			*(u32 *)val = obj->integer.value;
			break;
		default:
			*(u64 *)val = obj->integer.value;
			break;
		}
	} else if (proptype == DEV_PROP_STRING) {
		ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
		if (ret)
			return ret;

		*(char **)val = obj->string.pointer;
	} else {
		ret = -EINVAL;
	}
	return ret;
}
Esempio n. 2
0
static acpi_status acpi_register_phy(acpi_handle handle, u32 lvl,
				     void *context, void **ret)
{
	struct mii_bus *mdio = context;
	struct acpi_device *adev;
	struct phy_device *phy_dev;
	const union acpi_object *obj;
	u32 phy_addr;

	if (acpi_bus_get_device(handle, &adev))
		return AE_OK;

	if (acpi_dev_get_property(adev, "phy-channel", ACPI_TYPE_INTEGER, &obj))
		return AE_OK;
	phy_addr = obj->integer.value;

	phy_dev = xgene_enet_phy_register(mdio, phy_addr);
	adev->driver_data = phy_dev;

	return AE_OK;
}
/**
 * acpi_dev_get_property_array - return an ACPI array property with given name
 * @adev: ACPI device to get property
 * @name: Name of the property
 * @type: Expected type of array elements
 * @obj: Location to store a pointer to the property value (if not NULL)
 *
 * Look up an array property with @name and store a pointer to the resulting
 * ACPI object at the location pointed to by @obj if found.
 *
 * Callers must not attempt to free the returned objects.  Those objects will be
 * freed by the ACPI core automatically during the removal of @adev.
 *
 * Return: %0 if array property (package) with @name has been found (success),
 *         %-EINVAL if the arguments are invalid,
 *         %-ENODATA if the property doesn't exist,
 *         %-EPROTO if the property is not a package or the type of its elements
 *           doesn't match @type.
 */
int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
				acpi_object_type type,
				const union acpi_object **obj)
{
	const union acpi_object *prop;
	int ret, i;

	ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
	if (ret)
		return ret;

	if (type != ACPI_TYPE_ANY) {
		/* Check that all elements are of correct type. */
		for (i = 0; i < prop->package.count; i++)
			if (prop->package.elements[i].type != type)
				return -EPROTO;
	}
	if (obj)
		*obj = prop;

	return 0;
}
int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
		      void **valptr)
{
	return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
				     (const union acpi_object **)valptr);
}
/**
 * acpi_dev_get_property_reference - returns handle to the referenced object
 * @adev: ACPI device to get property
 * @name: Name of the property
 * @size_prop: Name of the "size" property in referenced object
 * @index: Index of the reference to return
 * @args: Location to store the returned reference with optional arguments
 *
 * Find property with @name, verifify that it is a package containing at least
 * one object reference and if so, store the ACPI device object pointer to the
 * target object in @args->adev.
 *
 * If the reference includes arguments (@size_prop is not %NULL) follow the
 * reference and check whether or not there is an integer property @size_prop
 * under the target object and if so, whether or not its value matches the
 * number of arguments that follow the reference.  If there's more than one
 * reference in the property value package, @index is used to select the one to
 * return.
 *
 * Return: %0 on success, negative error code on failure.
 */
int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
				    const char *size_prop, size_t index,
				    struct acpi_reference_args *args)
{
	const union acpi_object *element, *end;
	const union acpi_object *obj;
	struct acpi_device *device;
	int ret, idx = 0;

	ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
	if (ret)
		return ret;

	/*
	 * The simplest case is when the value is a single reference.  Just
	 * return that reference then.
	 */
	if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
		if (size_prop || index)
			return -EINVAL;

		ret = acpi_bus_get_device(obj->reference.handle, &device);
		if (ret)
			return ret;

		args->adev = device;
		args->nargs = 0;
		return 0;
	}

	/*
	 * If it is not a single reference, then it is a package of
	 * references followed by number of ints as follows:
	 *
	 *  Package () { REF, INT, REF, INT, INT }
	 *
	 * The index argument is then used to determine which reference
	 * the caller wants (along with the arguments).
	 */
	if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
		return -EPROTO;

	element = obj->package.elements;
	end = element + obj->package.count;

	while (element < end) {
		u32 nargs, i;

		if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
			return -EPROTO;

		ret = acpi_bus_get_device(element->reference.handle, &device);
		if (ret)
			return -ENODEV;

		element++;
		nargs = 0;

		if (size_prop) {
			const union acpi_object *prop;

			/*
			 * Find out how many arguments the refenced object
			 * expects by reading its size_prop property.
			 */
			ret = acpi_dev_get_property(device, size_prop,
						    ACPI_TYPE_INTEGER, &prop);
			if (ret)
				return ret;

			nargs = prop->integer.value;
			if (nargs > MAX_ACPI_REFERENCE_ARGS
			    || element + nargs > end)
				return -EPROTO;

			/*
			 * Skip to the start of the arguments and verify
			 * that they all are in fact integers.
			 */
			for (i = 0; i < nargs; i++)
				if (element[i].type != ACPI_TYPE_INTEGER)
					return -EPROTO;
		} else {
			/* assume following integer elements are all args */
			for (i = 0; element + i < end; i++) {
				int type = element[i].type;

				if (type == ACPI_TYPE_INTEGER)
					nargs++;
				else if (type == ACPI_TYPE_LOCAL_REFERENCE)
					break;
				else
					return -EPROTO;
			}
		}

		if (idx++ == index) {
			args->adev = device;
			args->nargs = nargs;
			for (i = 0; i < nargs; i++)
				args->args[i] = element[i].integer.value;

			return 0;
		}

		element += nargs;
	}

	return -EPROTO;
}