[alsa-devel] [PATCH 4/4] firewire-speakers: add functions to handle payload

Takashi Sakamoto o-takashi at sakamocchi.jp
Wed Jul 17 13:50:48 CEST 2013


From: sakamocchi <o-takashi at sakamocchi.jp>

With my previous three patches, each driver can handle payload of AMDTP packet.
This commit adapts existed firewire-speakers driver to it.

Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
 speakers.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 88 insertions(+), 6 deletions(-)

diff --git a/speakers.c b/speakers.c
index 2c63865..a0b0b14 100644
--- a/speakers.c
+++ b/speakers.c
@@ -50,6 +50,7 @@ struct fwspk {
 	struct fw_unit *unit;
 	const struct device_info *device_info;
 	struct snd_pcm_substream *pcm;
+	unsigned int pcm_channels;
 	struct mutex mutex;
 	struct cmp_connection connection;
 	struct amdtp_out_stream stream;
@@ -147,7 +148,7 @@ static int fwspk_open(struct snd_pcm_substream *substream)
 			SNDRV_PCM_INFO_BATCH |
 			SNDRV_PCM_INFO_INTERLEAVED |
 			SNDRV_PCM_INFO_BLOCK_TRANSFER,
-		.formats = AMDTP_OUT_PCM_FORMAT_BITS,
+		.formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32,
 		.channels_min = 2,
 		.channels_max = 2,
 		.buffer_bytes_max = 4 * 1024 * 1024,
@@ -247,11 +248,10 @@ static int fwspk_hw_params(struct snd_pcm_substream *substream,
 	if (err < 0)
 		goto error;
 
+	fwspk->pcm_channels = params_channels(hw_params);
 	amdtp_out_stream_set_rate(&fwspk->stream, params_rate(hw_params));
-	amdtp_out_stream_set_pcm(&fwspk->stream, params_channels(hw_params));
-
-	amdtp_out_stream_set_pcm_format(&fwspk->stream,
-					params_format(hw_params));
+	amdtp_out_stream_set_data_block_quadlets(&fwspk->stream,
+						 params_channels(hw_params));
 
 	err = fwspk_set_rate(fwspk, fwspk->stream.sfc);
 	if (err < 0)
@@ -276,6 +276,87 @@ static int fwspk_hw_free(struct snd_pcm_substream *substream)
 	return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
+static void write_silence(struct amdtp_out_stream *s,
+			  __be32 *buffer, unsigned int data_blocks)
+{
+	struct fwspk *fwspk = container_of(s, struct fwspk, stream);
+	unsigned int i, c;
+
+	for (i = 0; i < data_blocks; i++) {
+		for (c = 0; c < fwspk->pcm_channels; c++)
+			buffer[c] = cpu_to_be32(0x40000000);
+		buffer += s->data_block_quadlets;
+	}
+}
+
+static unsigned int write_s32(struct amdtp_out_stream *s,
+			      struct snd_pcm_runtime *runtime,
+			      __be32 *buffer, unsigned int data_blocks)
+{
+	struct fwspk *fwspk = container_of(s, struct fwspk, stream);
+	unsigned int remaining_frames, frames, i, c;
+	const u32 *src;
+
+	src = (void *)runtime->dma_area +
+			bytes_to_frames(runtime, s->pcm_buffer_pointer);
+	remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+	frames = 0;
+	for (i = 0; i < data_blocks; i++) {
+		for (c = 0; c < fwspk->pcm_channels; c++) {
+			buffer[c] = cpu_to_be32((*src >> 8) | 0x40000000);
+			src++;
+		}
+		buffer += s->data_block_quadlets;
+		frames++;
+		if (--remaining_frames == 0)
+			src = (void *)runtime->dma_area;
+	}
+	return frames;
+}
+
+static unsigned int write_s16(struct amdtp_out_stream *s,
+			      struct snd_pcm_runtime *runtime,
+			      __be32 *buffer, unsigned int data_blocks)
+{
+	struct fwspk *fwspk = container_of(s, struct fwspk, stream);
+	unsigned int remaining_frames, frames, i, c;
+	const u16 *src;
+
+	src = (void *)runtime->dma_area +
+			bytes_to_frames(runtime, s->pcm_buffer_pointer);
+	remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+	frames = 0;
+	for (i = 0; i < data_blocks; i++) {
+		for (c = 0; c < fwspk->pcm_channels; c++) {
+			buffer[c] = cpu_to_be32((*src << 8) | 0x400000000);
+			src++;
+		}
+		buffer += s->data_block_quadlets;
+		frames++;
+		if (--remaining_frames == 0)
+			src = (void *)runtime->dma_area;
+	}
+	return frames;
+}
+
+static unsigned int write_payload(struct amdtp_out_stream *s,
+				  struct snd_pcm_substream *pcm,
+				  __be32 *buffer, unsigned int data_blocks)
+{
+	buffer += 2;
+
+	if (!pcm) {
+		write_silence(s, buffer, data_blocks);
+		return 0;
+	} else if ((pcm->runtime->format == SNDRV_PCM_FORMAT_S32_LE) ||
+                   (pcm->runtime->format == SNDRV_PCM_FORMAT_S32_BE))
+		return write_s32(s, pcm->runtime, buffer, data_blocks);
+	else
+		return write_s16(s, pcm->runtime, buffer, data_blocks);
+}
+
 static int fwspk_prepare(struct snd_pcm_substream *substream)
 {
 	struct fwspk *fwspk = substream->private_data;
@@ -294,7 +375,8 @@ static int fwspk_prepare(struct snd_pcm_substream *substream)
 
 		err = amdtp_out_stream_start(&fwspk->stream,
 					fwspk->connection.resources.channel,
-					fwspk->connection.speed);
+					fwspk->connection.speed,
+					write_payload);
 		if (err < 0)
 			goto err_connection;
 
-- 
1.7.10.4



More information about the Alsa-devel mailing list