sound/core/control.c

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

File Facts

System
Linux kernel
Corpus path
sound/core/control.c
Extension
.c
Size
68331 bytes
Lines
2531
Domain
Driver Families
Bucket
sound/core
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations snd_ctl_f_ops =
{
	.owner =	THIS_MODULE,
	.read =		snd_ctl_read,
	.open =		snd_ctl_open,
	.release =	snd_ctl_release,
	.poll =		snd_ctl_poll,
	.unlocked_ioctl =	snd_ctl_ioctl,
	.compat_ioctl =	snd_ctl_ioctl_compat,
	.fasync =	snd_ctl_fasync,
};

/* call lops under rwsems; called from snd_ctl_dev_*() below() */
#define call_snd_ctl_lops(_card, _op)				    \
	do {							    \
		struct snd_ctl_layer_ops *lops;			    \
		guard(rwsem_read)(&(_card)->controls_rwsem);	    \
		guard(rwsem_read)(&snd_ctl_layer_rwsem);	    \
		for (lops = snd_ctl_layer; lops; lops = lops->next) \
			lops->_op(_card);			    \
	} while (0)

/*
 * registration of the control device
 */
static int snd_ctl_dev_register(struct snd_device *device)
{
	struct snd_card *card = device->device_data;
	int err;

	err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
				  &snd_ctl_f_ops, card, card->ctl_dev);
	if (err < 0)
		return err;
	call_snd_ctl_lops(card, lregister);
	return 0;
}

/*
 * disconnection of the control device
 */
static int snd_ctl_dev_disconnect(struct snd_device *device)
{
	struct snd_card *card = device->device_data;
	struct snd_ctl_file *ctl;

	scoped_guard(read_lock_irqsave, &card->controls_rwlock) {
		list_for_each_entry(ctl, &card->ctl_files, list) {
			wake_up(&ctl->change_sleep);
			snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
		}
	}

	call_snd_ctl_lops(card, ldisconnect);
	return snd_unregister_device(card->ctl_dev);
}

/*
 * free all controls
 */
static int snd_ctl_dev_free(struct snd_device *device)
{
	struct snd_card *card = device->device_data;
	struct snd_kcontrol *control;

	scoped_guard(rwsem_write, &card->controls_rwsem) {
		while (!list_empty(&card->controls)) {
			control = snd_kcontrol(card->controls.next);
			__snd_ctl_remove(card, control, false);
		}

#ifdef CONFIG_SND_CTL_FAST_LOOKUP
		xa_destroy(&card->ctl_numids);
		xa_destroy(&card->ctl_hash);
#endif
	}
	put_device(card->ctl_dev);
	return 0;
}

/*
 * create control core:
 * called from init.c
 */
int snd_ctl_create(struct snd_card *card)
{
	static const struct snd_device_ops ops = {
		.dev_free = snd_ctl_dev_free,
		.dev_register =	snd_ctl_dev_register,
		.dev_disconnect = snd_ctl_dev_disconnect,

Annotation

Implementation Notes