drivers/platform/x86/amd/wbrf.c

Source file repositories/reference/linux-study-clean/drivers/platform/x86/amd/wbrf.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/x86/amd/wbrf.c
Extension
.c
Size
8797 bytes
Lines
312
Domain
Driver Families
Bucket
drivers/platform
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct amd_wbrf_ranges_out {
	u32			num_of_ranges;
	struct freq_band_range	band_list[MAX_NUM_OF_WBRF_RANGES];
} __packed;

static const guid_t wifi_acpi_dsm_guid =
	GUID_INIT(0x7b7656cf, 0xdc3d, 0x4c1c,
		  0x83, 0xe9, 0x66, 0xe7, 0x21, 0xde, 0x30, 0x70);

/*
 * Used to notify consumer (amdgpu driver currently) about
 * the wifi frequency is change.
 */
static BLOCKING_NOTIFIER_HEAD(wbrf_chain_head);

static int wbrf_record(struct acpi_device *adev, uint8_t action, struct wbrf_ranges_in_out *in)
{
	union acpi_object argv4;
	u32 num_of_ranges = 0;
	u32 num_of_elements;
	u32 arg_idx = 0;
	int ret;
	u32 i;

	if (!in)
		return -EINVAL;

	for (i = 0; i < ARRAY_SIZE(in->band_list); i++) {
		if (in->band_list[i].start && in->band_list[i].end)
			num_of_ranges++;
	}

	/*
	 * The num_of_ranges value in the "in" object supplied by
	 * the caller is required to be equal to the number of
	 * entries in the band_list array in there.
	 */
	if (num_of_ranges != in->num_of_ranges)
		return -EINVAL;

	/*
	 * Every input frequency band comes with two end points(start/end)
	 * and each is accounted as an element. Meanwhile the range count
	 * and action type are accounted as an element each.
	 * So, the total element count = 2 * num_of_ranges + 1 + 1.
	 */
	num_of_elements = 2 * num_of_ranges + 2;

	union acpi_object *tmp __free(kfree) = kzalloc_objs(*tmp,
							    num_of_elements);
	if (!tmp)
		return -ENOMEM;

	argv4.package.type = ACPI_TYPE_PACKAGE;
	argv4.package.count = num_of_elements;
	argv4.package.elements = tmp;

	/* save the number of ranges*/
	tmp[0].integer.type = ACPI_TYPE_INTEGER;
	tmp[0].integer.value = num_of_ranges;

	/* save the action(WBRF_RECORD_ADD/REMOVE/RETRIEVE) */
	tmp[1].integer.type = ACPI_TYPE_INTEGER;
	tmp[1].integer.value = action;

	arg_idx = 2;
	for (i = 0; i < ARRAY_SIZE(in->band_list); i++) {
		if (!in->band_list[i].start || !in->band_list[i].end)
			continue;

		tmp[arg_idx].integer.type = ACPI_TYPE_INTEGER;
		tmp[arg_idx++].integer.value = in->band_list[i].start;
		tmp[arg_idx].integer.type = ACPI_TYPE_INTEGER;
		tmp[arg_idx++].integer.value = in->band_list[i].end;
	}

	union acpi_object *obj __free(kfree) =
		acpi_evaluate_dsm(adev->handle, &wifi_acpi_dsm_guid,
				  WBRF_REVISION, WBRF_RECORD, &argv4);

	if (!obj)
		return -EINVAL;

	if (obj->type != ACPI_TYPE_INTEGER)
		return -EINVAL;

	ret = obj->integer.value;
	if (ret)
		return -EINVAL;

Annotation

Implementation Notes