sound/firewire/tascam/tascam-hwdep.c

Source file repositories/reference/linux-study-clean/sound/firewire/tascam/tascam-hwdep.c

File Facts

System
Linux kernel
Corpus path
sound/firewire/tascam/tascam-hwdep.c
Extension
.c
Size
6079 bytes
Lines
262
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * tascam-hwdep.c - a part of driver for TASCAM FireWire series
 *
 * Copyright (c) 2015 Takashi Sakamoto
 */

/*
 * This codes give three functionality.
 *
 * 1.get firewire node information
 * 2.get notification about starting/stopping stream
 * 3.lock/unlock stream
 */

#include "tascam.h"

static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
				   long count, loff_t *offset)
	__releases(&tscm->lock)
{
	struct snd_firewire_event_lock_status event = {
		.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
	};

	event.status = (tscm->dev_lock_count > 0);
	tscm->dev_lock_changed = false;
	count = min_t(long, count, sizeof(event));

	spin_unlock_irq(&tscm->lock);

	if (copy_to_user(buf, &event, count))
		return -EFAULT;

	return count;
}

static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
				  long remained, loff_t *offset)
	__releases(&tscm->lock)
{
	char __user *pos = buf;
	unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL;
	struct snd_firewire_tascam_change *entries = tscm->queue;
	long count;

	// At least, one control event can be copied.
	if (remained < sizeof(type) + sizeof(*entries)) {
		spin_unlock_irq(&tscm->lock);
		return -EINVAL;
	}

	// Copy the type field later.
	count = sizeof(type);
	remained -= sizeof(type);
	pos += sizeof(type);

	while (true) {
		unsigned int head_pos;
		unsigned int tail_pos;
		unsigned int length;

		if (tscm->pull_pos == tscm->push_pos)
			break;
		else if (tscm->pull_pos < tscm->push_pos)
			tail_pos = tscm->push_pos;
		else
			tail_pos = SND_TSCM_QUEUE_COUNT;
		head_pos = tscm->pull_pos;

		length = (tail_pos - head_pos) * sizeof(*entries);
		if (remained < length)
			length = rounddown(remained, sizeof(*entries));
		if (length == 0)
			break;
		tail_pos = head_pos + length / sizeof(*entries);

		spin_unlock_irq(&tscm->lock);
		if (copy_to_user(pos, &entries[head_pos], length))
			return -EFAULT;

		spin_lock_irq(&tscm->lock);

		tscm->pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT;

		count += length;
		remained -= length;
		pos += length;
	}

Annotation

Implementation Notes