sound/firewire/digi00x/digi00x-pcm.c

Source file repositories/reference/linux-study-clean/sound/firewire/digi00x/digi00x-pcm.c

File Facts

System
Linux kernel
Corpus path
sound/firewire/digi00x/digi00x-pcm.c
Extension
.c
Size
8775 bytes
Lines
347
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

if (!detect) {
			err = -EBUSY;
			goto err_locked;
		}
	}

	scoped_guard(mutex, &dg00x->mutex) {
		// When source of clock is not internal or any stream is reserved for
		// transmission of PCM frames, the available sampling rate is limited
		// at current one.
		if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
		    (dg00x->substreams_counter > 0 && d->events_per_period > 0)) {
			unsigned int frames_per_period = d->events_per_period;
			unsigned int frames_per_buffer = d->events_per_buffer;
			unsigned int rate;

			err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
			if (err < 0)
				goto err_locked;
			substream->runtime->hw.rate_min = rate;
			substream->runtime->hw.rate_max = rate;

			if (frames_per_period > 0) {
				err = snd_pcm_hw_constraint_minmax(substream->runtime,
								   SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
								   frames_per_period, frames_per_period);
				if (err < 0)
					goto err_locked;

				err = snd_pcm_hw_constraint_minmax(substream->runtime,
								   SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
								   frames_per_buffer, frames_per_buffer);
				if (err < 0)
					goto err_locked;
			}
		}
	}

	snd_pcm_set_sync(substream);

	return 0;
err_locked:
	snd_dg00x_stream_lock_release(dg00x);
	return err;
}

static int pcm_close(struct snd_pcm_substream *substream)
{
	struct snd_dg00x *dg00x = substream->private_data;

	snd_dg00x_stream_lock_release(dg00x);

	return 0;
}

static int pcm_hw_params(struct snd_pcm_substream *substream,
			 struct snd_pcm_hw_params *hw_params)
{
	struct snd_dg00x *dg00x = substream->private_data;
	int err = 0;

	if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {
		unsigned int rate = params_rate(hw_params);
		unsigned int frames_per_period = params_period_size(hw_params);
		unsigned int frames_per_buffer = params_buffer_size(hw_params);

		guard(mutex)(&dg00x->mutex);
		err = snd_dg00x_stream_reserve_duplex(dg00x, rate,
					frames_per_period, frames_per_buffer);
		if (err >= 0)
			++dg00x->substreams_counter;
	}

	return err;
}

static int pcm_hw_free(struct snd_pcm_substream *substream)
{
	struct snd_dg00x *dg00x = substream->private_data;

	guard(mutex)(&dg00x->mutex);

	if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
		--dg00x->substreams_counter;

	snd_dg00x_stream_stop_duplex(dg00x);

	return 0;
}

Annotation

Implementation Notes