sound/firewire/fireworks/fireworks_transaction.c

Source file repositories/reference/linux-study-clean/sound/firewire/fireworks/fireworks_transaction.c

File Facts

System
Linux kernel
Corpus path
sound/firewire/fireworks/fireworks_transaction.c
Extension
.c
Size
7872 bytes
Lines
314
Domain
Driver Families
Bucket
sound/firewire
Inferred role
Driver Families: implementation source
Status
source 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 transaction_queue {
	struct list_head list;
	struct fw_unit *unit;
	void *buf;
	unsigned int size;
	u32 seqnum;
	enum transaction_queue_state state;
	wait_queue_head_t wait;
};

int snd_efw_transaction_cmd(struct fw_unit *unit,
			    const void *cmd, unsigned int size)
{
	return snd_fw_transaction(unit, TCODE_WRITE_BLOCK_REQUEST,
				  MEMORY_SPACE_EFW_COMMAND,
				  (void *)cmd, size, 0);
}

int snd_efw_transaction_run(struct fw_unit *unit,
			    const void *cmd, unsigned int cmd_size,
			    void *resp, unsigned int resp_size)
{
	struct transaction_queue t;
	unsigned int tries;
	int ret;

	t.unit = unit;
	t.buf = resp;
	t.size = resp_size;
	t.seqnum = be32_to_cpu(((struct snd_efw_transaction *)cmd)->seqnum) + 1;
	t.state = STATE_PENDING;
	init_waitqueue_head(&t.wait);

	scoped_guard(spinlock_irq, &transaction_queues_lock) {
		list_add_tail(&t.list, &transaction_queues);
	}

	tries = 0;
	do {
		ret = snd_efw_transaction_cmd(t.unit, (void *)cmd, cmd_size);
		if (ret < 0)
			break;

		wait_event_timeout(t.wait, t.state != STATE_PENDING,
				   msecs_to_jiffies(EFC_TIMEOUT_MS));

		if (t.state == STATE_COMPLETE) {
			ret = t.size;
			break;
		} else if (t.state == STATE_BUS_RESET) {
			msleep(ERROR_DELAY_MS);
		} else if (++tries >= ERROR_RETRIES) {
			dev_err(&t.unit->device, "EFW transaction timed out\n");
			ret = -EIO;
			break;
		}
	} while (1);

	scoped_guard(spinlock_irq, &transaction_queues_lock) {
		list_del(&t.list);
	}

	return ret;
}

static void
copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
{
	size_t capacity, till_end;
	struct snd_efw_transaction *t;

	t = (struct snd_efw_transaction *)data;
	length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);

	guard(spinlock)(&efw->lock);

	if (efw->push_ptr < efw->pull_ptr)
		capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
	else
		capacity = snd_efw_resp_buf_size -
			   (unsigned int)(efw->push_ptr - efw->pull_ptr);

	/* confirm enough space for this response */
	if (capacity < length) {
		*rcode = RCODE_CONFLICT_ERROR;
		return;
	}

	/* copy to ring buffer */
	while (length > 0) {

Annotation

Implementation Notes