+static void handle_in_packet(struct amdtp_stream *s,
+ unsigned int payload_quadlets,
+ __be32 *buffer)
+{
+ u32 cip_header[2];
+ unsigned int data_blocks, data_block_quadlets, data_block_counter;
+ struct snd_pcm_substream *pcm = NULL;
+
+ cip_header[0] = be32_to_cpu(buffer[0]);
+ cip_header[1] = be32_to_cpu(buffer[1]);
+
+ /*
+ * This module supports 'Two-quadlet CIP header with SYT field'.
+ * For convinience, also check FMT field is AM824 or not.
+ */
+ if (((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) ||
+ ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH) ||
+ ((cip_header[1] & CIP_FMT_MASK) != CIP_FMT_AM)) {
+ dev_info_ratelimited(&s->unit->device,
+ "Invalid CIP header for AMDTP: %08X:%08X\n",
+ cip_header[0], cip_header[1]);
+ goto end;
+ }
+
+ /* Calculate data blocks */
+ if (payload_quadlets < 3 ||
+ ((cip_header[1] & CIP_FDF_MASK) ==
+ (AMDTP_FDF_NO_DATA << CIP_FDF_SFC_SHIFT))) {
+ data_blocks = 0;
+ } else {
+ data_block_quadlets =
+ (cip_header[0] & AMDTP_DBS_MASK) >> AMDTP_DBS_SHIFT;
+ /* avoid division by zero */
+ if (data_block_quadlets == 0) {
+ dev_info_ratelimited(&s->unit->device,
+ "Detect invalid value in dbs field: %08X\n",
+ cip_header[0]);
+ goto err;
+ }
+
+ data_blocks = (payload_quadlets - 2) / data_block_quadlets;
+ }
+
+ /* Check data block counter continuity */
+ data_block_counter = cip_header[0] & AMDTP_DBC_MASK;
+ if (data_block_counter != s->data_block_counter) {
+ dev_info(&s->unit->device,
+ "Detect discontinuity of CIP: %02X %02X\n",
+ s->data_block_counter, data_block_counter);
+ goto err;
+ }
+
+ if (data_blocks > 0) {
+ buffer += 2;
+
+ pcm = ACCESS_ONCE(s->pcm);
+ if (pcm)
+ s->transfer_samples(s, pcm, buffer, data_blocks);
+ }
+
+ s->data_block_counter = (data_block_counter + data_blocks) & 0xff;
+end:
+ if (queue_in_packet(s) < 0)
+ goto err;
+
+ if (pcm)
+ update_pcm_pointers(s, pcm, data_blocks);
+
+ return;
+err:
+ s->packet_index = -1;
+ amdtp_stream_pcm_abort(s);
+}
+