sound/core/misc.c

Source file repositories/reference/linux-study-clean/sound/core/misc.c

File Facts

System
Linux kernel
Corpus path
sound/core/misc.c
Extension
.c
Size
4830 bytes
Lines
201
Domain
Driver Families
Bucket
sound/core
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 snd_fasync {
	struct fasync_struct *fasync;
	int signal;
	int poll;
	int on;
	struct list_head list;
};

static DEFINE_SPINLOCK(snd_fasync_lock);
static LIST_HEAD(snd_fasync_list);

static void snd_fasync_work_fn(struct work_struct *work)
{
	struct snd_fasync *fasync;
	int signal, poll;

	spin_lock_irq(&snd_fasync_lock);
	while (!list_empty(&snd_fasync_list)) {
		fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list);
		list_del_init(&fasync->list);
		if (!fasync->on)
			continue;
		signal = fasync->signal;
		poll = fasync->poll;
		spin_unlock_irq(&snd_fasync_lock);
		kill_fasync(&fasync->fasync, signal, poll);
		spin_lock_irq(&snd_fasync_lock);
	}
	spin_unlock_irq(&snd_fasync_lock);
}

static DECLARE_WORK(snd_fasync_work, snd_fasync_work_fn);

int snd_fasync_helper(int fd, struct file *file, int on,
		      struct snd_fasync **fasyncp)
{
	struct snd_fasync *fasync = NULL;

	if (on) {
		fasync = kzalloc(sizeof(*fasync), GFP_KERNEL);
		if (!fasync)
			return -ENOMEM;
		INIT_LIST_HEAD(&fasync->list);
	}

	scoped_guard(spinlock_irq, &snd_fasync_lock) {
		if (*fasyncp) {
			kfree(fasync);
			fasync = *fasyncp;
		} else {
			if (!fasync)
				return 0;
			*fasyncp = fasync;
		}
		fasync->on = on;
	}
	return fasync_helper(fd, file, on, &fasync->fasync);
}
EXPORT_SYMBOL_GPL(snd_fasync_helper);

void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll)
{
	if (!fasync)
		return;
	guard(spinlock_irqsave)(&snd_fasync_lock);
	if (!fasync->on)
		return;
	fasync->signal = signal;
	fasync->poll = poll;
	list_move(&fasync->list, &snd_fasync_list);
	schedule_work(&snd_fasync_work);
}
EXPORT_SYMBOL_GPL(snd_kill_fasync);

void snd_fasync_free(struct snd_fasync *fasync)
{
	if (!fasync)
		return;

	scoped_guard(spinlock_irq, &snd_fasync_lock) {
		fasync->on = 0;
		list_del_init(&fasync->list);
	}

	flush_work(&snd_fasync_work);
	kfree(fasync);
}
EXPORT_SYMBOL_GPL(snd_fasync_free);

/*

Annotation

Implementation Notes