Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e335425b authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai
Browse files

ALSA: firewire-lib: split helper function to check incoming CIP header



A parser for CIP header in incoming packet is enough large.

This commit splits it into a helper function to better looks of packet
handler.

Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 8a400b99
Loading
Loading
Loading
Loading
+60 −40
Original line number Diff line number Diff line
@@ -549,29 +549,19 @@ static int handle_out_packet_without_header(struct amdtp_stream *s,
	return 0;
}

static int handle_in_packet(struct amdtp_stream *s, unsigned int cycle,
			    const __be32 *ctx_header, __be32 *buffer,
			    unsigned int index)
static int check_cip_header(struct amdtp_stream *s, const __be32 *buf,
			    unsigned int payload_length,
			    unsigned int *data_blocks, unsigned int *syt)
{
	unsigned int payload_length;
	u32 cip_header[2];
	unsigned int sph, fmt, fdf, syt;
	unsigned int data_block_quadlets, data_block_counter, dbc_interval;
	unsigned int data_blocks;
	struct snd_pcm_substream *pcm;
	unsigned int pcm_frames;
	unsigned int sph;
	unsigned int fmt;
	unsigned int fdf;
	unsigned int data_block_counter;
	bool lost;

	payload_length = be32_to_cpu(ctx_header[0]) >> ISO_DATA_LENGTH_SHIFT;
	if (payload_length > s->ctx_data.tx.max_payload_length) {
		dev_err(&s->unit->device,
			"Detect jumbo payload: %04x %04x\n",
			payload_length, s->ctx_data.tx.max_payload_length);
		return -EIO;
	}

	cip_header[0] = be32_to_cpu(buffer[0]);
	cip_header[1] = be32_to_cpu(buffer[1]);
	cip_header[0] = be32_to_cpu(buf[0]);
	cip_header[1] = be32_to_cpu(buf[1]);

	/*
	 * This module supports 'Two-quadlet CIP header with SYT field'.
@@ -583,9 +573,7 @@ static int handle_in_packet(struct amdtp_stream *s, unsigned int cycle,
		dev_info_ratelimited(&s->unit->device,
				"Invalid CIP header for AMDTP: %08X:%08X\n",
				cip_header[0], cip_header[1]);
		data_blocks = 0;
		pcm_frames = 0;
		goto end;
		return -EAGAIN;
	}

	/* Check valid protocol or not. */
@@ -595,18 +583,16 @@ static int handle_in_packet(struct amdtp_stream *s, unsigned int cycle,
		dev_info_ratelimited(&s->unit->device,
				     "Detect unexpected protocol: %08x %08x\n",
				     cip_header[0], cip_header[1]);
		data_blocks = 0;
		pcm_frames = 0;
		goto end;
		return -EAGAIN;
	}

	/* Calculate data blocks */
	fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT;
	if (payload_length < 12 ||
	if (payload_length < sizeof(__be32) * 2 ||
	    (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) {
		data_blocks = 0;
		*data_blocks = 0;
	} else {
		data_block_quadlets =
		unsigned int data_block_quadlets =
				(cip_header[0] & CIP_DBS_MASK) >> CIP_DBS_SHIFT;
		/* avoid division by zero */
		if (data_block_quadlets == 0) {
@@ -618,13 +604,13 @@ static int handle_in_packet(struct amdtp_stream *s, unsigned int cycle,
		if (s->flags & CIP_WRONG_DBS)
			data_block_quadlets = s->data_block_quadlets;

		data_blocks = (payload_length / 4 - 2) /
		*data_blocks = (payload_length / sizeof(__be32) - 2) /
							data_block_quadlets;
	}

	/* Check data block counter continuity */
	data_block_counter = cip_header[0] & CIP_DBC_MASK;
	if (data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
	if (*data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
	    s->data_block_counter != UINT_MAX)
		data_block_counter = s->data_block_counter;

@@ -635,10 +621,12 @@ static int handle_in_packet(struct amdtp_stream *s, unsigned int cycle,
	} else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
		lost = data_block_counter != s->data_block_counter;
	} else {
		if (data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0)
		unsigned int dbc_interval;

		if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0)
			dbc_interval = s->ctx_data.tx.dbc_interval;
		else
			dbc_interval = data_blocks;
			dbc_interval = *data_blocks;

		lost = data_block_counter !=
		       ((s->data_block_counter + dbc_interval) & 0xff);
@@ -651,16 +639,48 @@ static int handle_in_packet(struct amdtp_stream *s, unsigned int cycle,
		return -EIO;
	}

	trace_amdtp_packet(s, cycle, buffer, payload_length, data_blocks, index);
	*syt = cip_header[1] & CIP_SYT_MASK;

	syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
	pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);

	if (s->flags & CIP_DBC_IS_END_EVENT)
	if (s->flags & CIP_DBC_IS_END_EVENT) {
		s->data_block_counter = data_block_counter;
	else
	} else {
		s->data_block_counter =
				(data_block_counter + data_blocks) & 0xff;
				(data_block_counter + *data_blocks) & 0xff;
	}

	return 0;
}

static int handle_in_packet(struct amdtp_stream *s, unsigned int cycle,
			    const __be32 *ctx_header, __be32 *buffer,
			    unsigned int index)
{
	unsigned int payload_length;
	unsigned int syt;
	unsigned int data_blocks;
	struct snd_pcm_substream *pcm;
	unsigned int pcm_frames;
	int err;

	payload_length = be32_to_cpu(ctx_header[0]) >> ISO_DATA_LENGTH_SHIFT;
	if (payload_length > s->ctx_data.tx.max_payload_length) {
		dev_err(&s->unit->device,
			"Detect jumbo payload: %04x %04x\n",
			payload_length, s->ctx_data.tx.max_payload_length);
		return -EIO;
	}

	err = check_cip_header(s, buffer, payload_length, &data_blocks, &syt);
	if (err < 0) {
		if (err != -EAGAIN)
			return err;
		pcm_frames = 0;
		goto end;
	}

	trace_amdtp_packet(s, cycle, buffer, payload_length, data_blocks, index);

	pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
end:
	if (queue_in_packet(s) < 0)
		return -EIO;