drivers/dma/acpi-dma.c

Source file repositories/reference/linux-study-clean/drivers/dma/acpi-dma.c

File Facts

System
Linux kernel
Corpus path
drivers/dma/acpi-dma.c
Extension
.c
Size
13091 bytes
Lines
463
Domain
Driver Families
Bucket
drivers/dma
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 acpi_dma_parser_data {
	struct acpi_dma_spec dma_spec;
	size_t index;
	size_t n;
};

/**
 * acpi_dma_parse_fixed_dma - Parse FixedDMA ACPI resources to a DMA specifier
 * @res:	struct acpi_resource to get FixedDMA resources from
 * @data:	pointer to a helper struct acpi_dma_parser_data
 */
static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data)
{
	struct acpi_dma_parser_data *pdata = data;

	if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) {
		struct acpi_resource_fixed_dma *dma = &res->data.fixed_dma;

		if (pdata->n++ == pdata->index) {
			pdata->dma_spec.chan_id = dma->channels;
			pdata->dma_spec.slave_id = dma->request_lines;
		}
	}

	/* Tell the ACPI core to skip this resource */
	return 1;
}

/**
 * acpi_dma_request_slave_chan_by_index - Get the DMA slave channel
 * @dev:	struct device to get DMA request from
 * @index:	index of FixedDMA descriptor for @dev
 *
 * Return:
 * Pointer to appropriate dma channel on success or an error pointer.
 */
struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
		size_t index)
{
	struct acpi_dma_parser_data pdata;
	struct acpi_dma_spec *dma_spec = &pdata.dma_spec;
	struct acpi_device *adev = ACPI_COMPANION(dev);
	struct list_head resource_list;
	struct acpi_dma *adma;
	struct dma_chan *chan = NULL;
	int found;
	int ret;

	memset(&pdata, 0, sizeof(pdata));
	pdata.index = index;

	/* Initial values for the request line and channel */
	dma_spec->chan_id = -1;
	dma_spec->slave_id = -1;

	INIT_LIST_HEAD(&resource_list);
	ret = acpi_dev_get_resources(adev, &resource_list,
				     acpi_dma_parse_fixed_dma, &pdata);
	acpi_dev_free_resource_list(&resource_list);
	if (ret < 0)
		return ERR_PTR(ret);

	if (dma_spec->slave_id < 0 || dma_spec->chan_id < 0)
		return ERR_PTR(-ENODEV);

	mutex_lock(&acpi_dma_lock);

	list_for_each_entry(adma, &acpi_dma_list, dma_controllers) {
		/*
		 * We are not going to call translation function if slave_id
		 * doesn't fall to the request range.
		 */
		found = acpi_dma_update_dma_spec(adma, dma_spec);
		if (found < 0)
			continue;
		chan = adma->acpi_dma_xlate(dma_spec, adma);
		/*
		 * Try to get a channel only from the DMA controller that
		 * matches the slave_id. See acpi_dma_update_dma_spec()
		 * description for the details.
		 */
		if (found > 0 || chan)
			break;
	}

	mutex_unlock(&acpi_dma_lock);
	return chan ? chan : ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);

Annotation

Implementation Notes