void acpi_extract_apple_properties()

in x86/apple.c [27:138]


void acpi_extract_apple_properties(struct acpi_device *adev)
{
	unsigned int i, j = 0, newsize = 0, numprops, numvalid;
	union acpi_object *props, *newprops;
	unsigned long *valid = NULL;
	void *free_space;

	if (!x86_apple_machine)
		return;

	props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0,
					NULL, ACPI_TYPE_BUFFER);
	if (!props)
		return;

	if (!props->buffer.length)
		goto out_free;

	if (props->buffer.pointer[0] != 3) {
		acpi_handle_info(adev->handle, FW_INFO
				 "unsupported properties version %*ph\n",
				 props->buffer.length, props->buffer.pointer);
		goto out_free;
	}

	ACPI_FREE(props);
	props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1,
					NULL, ACPI_TYPE_PACKAGE);
	if (!props)
		return;

	numprops = props->package.count / 2;
	if (!numprops)
		goto out_free;

	valid = bitmap_zalloc(numprops, GFP_KERNEL);
	if (!valid)
		goto out_free;

	/* newsize = key length + value length of each tuple */
	for (i = 0; i < numprops; i++) {
		union acpi_object *key = &props->package.elements[i * 2];
		union acpi_object *val = &props->package.elements[i * 2 + 1];

		if ( key->type != ACPI_TYPE_STRING ||
		    (val->type != ACPI_TYPE_INTEGER &&
		     val->type != ACPI_TYPE_BUFFER))
			continue; /* skip invalid properties */

		__set_bit(i, valid);
		newsize += key->string.length + 1;
		if ( val->type == ACPI_TYPE_BUFFER)
			newsize += val->buffer.length;
	}

	numvalid = bitmap_weight(valid, numprops);
	if (numprops > numvalid)
		acpi_handle_info(adev->handle, FW_INFO
				 "skipped %u properties: wrong type\n",
				 numprops - numvalid);
	if (numvalid == 0)
		goto out_free;

	/* newsize += top-level package + 3 objects for each key/value tuple */
	newsize	+= (1 + 3 * numvalid) * sizeof(union acpi_object);
	newprops = ACPI_ALLOCATE_ZEROED(newsize);
	if (!newprops)
		goto out_free;

	/* layout: top-level package | packages | key/value tuples | strings */
	newprops->type = ACPI_TYPE_PACKAGE;
	newprops->package.count = numvalid;
	newprops->package.elements = &newprops[1];
	free_space = &newprops[1 + 3 * numvalid];

	for_each_set_bit(i, valid, numprops) {
		union acpi_object *key = &props->package.elements[i * 2];
		union acpi_object *val = &props->package.elements[i * 2 + 1];
		unsigned int k = 1 + numvalid + j * 2; /* index into newprops */
		unsigned int v = k + 1;

		newprops[1 + j].type = ACPI_TYPE_PACKAGE;
		newprops[1 + j].package.count = 2;
		newprops[1 + j].package.elements = &newprops[k];

		newprops[k].type = ACPI_TYPE_STRING;
		newprops[k].string.length = key->string.length;
		newprops[k].string.pointer = free_space;
		memcpy(free_space, key->string.pointer, key->string.length);
		free_space += key->string.length + 1;

		newprops[v].type = val->type;
		if (val->type == ACPI_TYPE_INTEGER) {
			newprops[v].integer.value = val->integer.value;
		} else {
			newprops[v].buffer.length = val->buffer.length;
			newprops[v].buffer.pointer = free_space;
			memcpy(free_space, val->buffer.pointer,
			       val->buffer.length);
			free_space += val->buffer.length;
		}
		j++; /* count valid properties */
	}
	WARN_ON(free_space != (void *)newprops + newsize);

	adev->data.pointer = newprops;
	acpi_data_add_props(&adev->data, &apple_prp_guid, newprops);

out_free:
	ACPI_FREE(props);
	bitmap_free(valid);
}