sound/soc/uniphier/aio-compress.c

Source file repositories/reference/linux-study-clean/sound/soc/uniphier/aio-compress.c

File Facts

System
Linux kernel
Corpus path
sound/soc/uniphier/aio-compress.c
Extension
.c
Size
11590 bytes
Lines
424
Domain
Driver Families
Bucket
sound/soc
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 (frm == IEC61937_HEADER_SIGN) {
			frm_a |= 0x01000000;

			/* Next data is Pc and Pd */
			sub->iec_header = true;
		} else {
			u16 pc = be16_to_cpu((__be16)frm_a);

			if (sub->iec_header && sub->iec_pc != pc) {
				/* Force overwrite IEC frame type */
				sub->iec_pc = pc;
				ret = aio_oport_set_stream_type(sub, pc);
				if (ret)
					return ret;
			}
			sub->iec_header = false;
		}
		dstbuf[dst++] = frm_a;
		dstbuf[dst++] = frm_b;

		dstsize -= sizeof(u32) * 2;
	}

	return 0;
}

static int uniphier_aio_compr_copy(struct snd_soc_component *component,
				   struct snd_compr_stream *cstream,
				   char __user *buf, size_t count)
{
	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
	struct snd_compr_runtime *runtime = cstream->runtime;
	struct device *carddev = rtd->compr->card->dev;
	struct uniphier_aio *aio = uniphier_priv(snd_soc_rtd_to_cpu(rtd, 0));
	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
	size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2);
	int bytes = runtime->fragment_size;
	size_t s;
	int ret;

	if (cnt < sizeof(u32))
		return 0;

	if (sub->swm->dir == PORT_DIR_OUTPUT) {
		dma_addr_t dmapos = sub->compr_addr + sub->wr_offs;

		/* Size of AIO output format is double of IEC61937 */
		s = cnt * 2;

		dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE);
		ret = aio_compr_send_to_hw(sub, buf, s);
		dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE);
	} else {
		dma_addr_t dmapos = sub->compr_addr + sub->rd_offs;

		s = cnt;

		dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE);
		ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s);
		dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE);
	}
	if (ret)
		return -EFAULT;

	guard(spinlock_irqsave)(&sub->lock);

	sub->threshold = 2 * bytes;
	aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes);

	if (sub->swm->dir == PORT_DIR_OUTPUT) {
		sub->wr_offs += s;
		if (sub->wr_offs >= sub->compr_bytes)
			sub->wr_offs -= sub->compr_bytes;
	} else {
		sub->rd_offs += s;
		if (sub->rd_offs >= sub->compr_bytes)
			sub->rd_offs -= sub->compr_bytes;
	}
	aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);

	return cnt;
}

static int uniphier_aio_compr_get_caps(struct snd_soc_component *component,
				       struct snd_compr_stream *cstream,
				       struct snd_compr_caps *caps)
{
	caps->num_codecs = 1;
	caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE;
	caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE;

Annotation

Implementation Notes