From: Takashi Sakamoto <o-takashi@sakamocchi.jp> To: clemens@ladisch.de, tiwai@suse.de, perex@perex.cz Cc: alsa-devel@alsa-project.org, ffado-devel@lists.sf.net Subject: [PATCH 05/39] firewire-lib: Add support for AMDTP in-stream and PCM capture Date: Wed, 5 Mar 2014 19:47:53 +0900 Message-ID: <1394016507-15761-6-git-send-email-o-takashi@sakamocchi.jp> (raw) In-Reply-To: <1394016507-15761-1-git-send-email-o-takashi@sakamocchi.jp> For capturing PCM, this commit adds the functionality to handle in-stream. This is also applied for dual-wire mode. Currently, capturing 32bit samples are supported. --- sound/firewire/amdtp.c | 218 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 201 insertions(+), 17 deletions(-) diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index ca79cb4..4ebfd67 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -39,6 +39,7 @@ * only "Clock-based rate control mode" is supported */ #define AMDTP_FDF_AM824 (0 << (CIP_FDF_SFC_SHIFT + 3)) +#define AMDTP_FDF_NO_DATA 0xff #define AMDTP_DBS_MASK 0x00ff0000 #define AMDTP_DBS_SHIFT 16 #define AMDTP_DBC_MASK 0x000000ff @@ -47,6 +48,7 @@ #define INTERRUPT_INTERVAL 16 #define QUEUE_LENGTH 48 +#define IN_PACKET_HEADER_SIZE 4 #define OUT_PACKET_HEADER_SIZE 0 static void pcm_period_tasklet(unsigned long data); @@ -179,6 +181,12 @@ static void amdtp_write_s16_dualwire(struct amdtp_stream *s, static void amdtp_write_s32_dualwire(struct amdtp_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames); +static void amdtp_read_s32(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames); +static void amdtp_read_s32_dualwire(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames); /** * amdtp_stream_set_pcm_format - set the PCM format @@ -200,16 +208,26 @@ void amdtp_stream_set_pcm_format(struct amdtp_stream *s, WARN_ON(1); /* fall through */ case SNDRV_PCM_FORMAT_S16: - if (s->dual_wire) - s->transfer_samples = amdtp_write_s16_dualwire; - else - s->transfer_samples = amdtp_write_s16; - break; + if (s->direction == AMDTP_OUT_STREAM) { + if (s->dual_wire) + s->transfer_samples = amdtp_write_s16_dualwire; + else + s->transfer_samples = amdtp_write_s16; + break; + } + WARN_ON(1); + /* fall through */ case SNDRV_PCM_FORMAT_S32: - if (s->dual_wire) - s->transfer_samples = amdtp_write_s32_dualwire; - else - s->transfer_samples = amdtp_write_s32; + if (s->direction == AMDTP_OUT_STREAM) { + if (s->dual_wire) + s->transfer_samples = amdtp_write_s32_dualwire; + else + s->transfer_samples = amdtp_write_s32; + } else if (s->dual_wire) { + s->transfer_samples = amdtp_read_s32_dualwire; + } else { + s->transfer_samples = amdtp_read_s32; + } break; } } @@ -420,6 +438,58 @@ static void amdtp_write_s16_dualwire(struct amdtp_stream *s, } } +static void amdtp_read_s32(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames) +{ + struct snd_pcm_runtime *runtime = pcm->runtime; + unsigned int remaining_frames, i, c; + u32 *dst; + + dst = (void *)runtime->dma_area + + frames_to_bytes(runtime, s->pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + + for (i = 0; i < frames; ++i) { + for (c = 0; c < s->pcm_channels; ++c) { + *dst = be32_to_cpu(buffer[c]) << 8; + dst++; + } + buffer += s->data_block_quadlets; + if (--remaining_frames == 0) + dst = (void *)runtime->dma_area; + } +} + +static void amdtp_read_s32_dualwire(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames) +{ + struct snd_pcm_runtime *runtime = pcm->runtime; + unsigned int channels, remaining_frames, i, c; + u32 *dst; + + dst = (void *)runtime->dma_area + + frames_to_bytes(runtime, s->pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + channels = s->pcm_channels / 2; + + for (i = 0; i < frames; ++i) { + for (c = 0; c < channels; ++c) { + *dst = be32_to_cpu(buffer[c * 2]) << 8; + dst++; + } + buffer += 1; + for (c = 0; c < channels; ++c) { + *dst = be32_to_cpu(buffer[c * 2]) << 8; + dst++; + } + buffer += s->data_block_quadlets - 1; + if (--remaining_frames == 0) + dst = (void *)runtime->dma_area; + } +} + static void amdtp_fill_pcm_silence(struct amdtp_stream *s, __be32 *buffer, unsigned int frames) { @@ -505,6 +575,12 @@ static inline int queue_out_packet(struct amdtp_stream *s, payload_length, skip); } +static inline int queue_in_packet(struct amdtp_stream *s) +{ + return queue_packet(s, IN_PACKET_HEADER_SIZE, + amdtp_stream_get_max_payload(s), false); +} + static void handle_out_packet(struct amdtp_stream *s, unsigned int cycle) { __be32 *buffer; @@ -552,6 +628,67 @@ static void handle_out_packet(struct amdtp_stream *s, unsigned int cycle) update_pcm_pointers(s, pcm, data_blocks); } +static void handle_in_packet(struct amdtp_stream *s, + unsigned int payload_quadlets, + __be32 *buffer) +{ + u32 cip_header[2]; + unsigned int data_block_quadlets, data_blocks, data_block_counter; + struct snd_pcm_substream *pcm; + + 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]); + return; + } + + /* ignore empty CIP packet or NO-DATA AMDTP packet */ + if ((payload_quadlets < 3) || + (((cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SFC_SHIFT) == + AMDTP_FDF_NO_DATA)) + return; + + data_block_quadlets = + (cip_header[1] & 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", + data_block_quadlets); + return; + } + + data_blocks = (payload_quadlets - 2) / data_block_quadlets; + data_block_counter = cip_header[1] & AMDTP_DBC_MASK; + + /* check packet continuity */ + s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; + if (s->data_block_counter != data_block_counter) { + dev_info_ratelimited(&s->unit->device, + "Detect uncontinuity of CIP packets\n"); + s->data_block_counter = data_block_counter; + return; + } + + buffer += 2; + + pcm = ACCESS_ONCE(s->pcm); + if (pcm) { + s->transfer_samples(s, pcm, buffer, data_blocks); + update_pcm_pointers(s, pcm, data_blocks); + } +} + static void out_stream_callback(struct fw_iso_context *context, u32 cycle, size_t header_length, void *header, void *private_data) @@ -571,6 +708,35 @@ static void out_stream_callback(struct fw_iso_context *context, u32 cycle, fw_iso_context_queue_flush(s->context); } +static void in_stream_callback(struct fw_iso_context *context, u32 cycle, + size_t header_length, void *header, + void *private_data) +{ + struct amdtp_stream *s = private_data; + unsigned int p, packets, data_quadlets; + __be32 *buffer, *headers = header; + + /* The number of packets in buffer */ + packets = header_length / IN_PACKET_HEADER_SIZE; + + for (p = 0; p < packets; p++) { + buffer = s->buffer.packets[s->packet_index].buffer; + + /* The number of quadlets in this packet */ + data_quadlets = + (be32_to_cpu(headers[p]) >> ISO_DATA_LENGTH_SHIFT) / 4; + /* handle each packet data */ + handle_in_packet(s, data_quadlets, buffer); + + if (queue_in_packet(s) < 0) { + amdtp_stream_pcm_abort(s); + return; + } + } + + fw_iso_context_queue_flush(s->context); +} + /** * amdtp_stream_start - start transferring packets * @s: the AMDTP stream to start @@ -595,7 +761,10 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) [CIP_SFC_88200] = { 0, 67 }, [CIP_SFC_176400] = { 0, 67 }, }; - int err; + unsigned int header_size; + enum dma_data_direction dir; + fw_iso_callback_t cb; + int type, err; mutex_lock(&s->mutex); @@ -609,16 +778,26 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) s->syt_offset_state = initial_state[s->sfc].syt_offset; s->last_syt_offset = TICKS_PER_CYCLE; + /* initialize packet buffer */ + if (s->direction == AMDTP_IN_STREAM) { + dir = DMA_FROM_DEVICE; + type = FW_ISO_CONTEXT_RECEIVE; + header_size = IN_PACKET_HEADER_SIZE; + cb = in_stream_callback; + } else { + dir = DMA_TO_DEVICE; + type = FW_ISO_CONTEXT_TRANSMIT; + header_size = OUT_PACKET_HEADER_SIZE; + cb = out_stream_callback; + } err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH, - amdtp_stream_get_max_payload(s), - DMA_TO_DEVICE); + amdtp_stream_get_max_payload(s), dir); if (err < 0) goto err_unlock; s->context = fw_iso_context_create(fw_parent_device(s->unit)->card, - FW_ISO_CONTEXT_TRANSMIT, - channel, speed, 0, - out_stream_callback, s); + type, channel, speed, header_size, + cb, s); if (IS_ERR(s->context)) { err = PTR_ERR(s->context); if (err == -EBUSY) @@ -631,13 +810,18 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) s->packet_index = 0; do { - err = queue_out_packet(s, 0, true); + if (s->direction == AMDTP_IN_STREAM) + err = queue_in_packet(s); + else + err = queue_out_packet(s, 0, true); if (err < 0) goto err_context; } while (s->packet_index > 0); + /* NOTE: TAG1 matches CIP. This just affects in stream */ s->data_block_counter = 0; - err = fw_iso_context_start(s->context, -1, 0, 0); + err = fw_iso_context_start(s->context, -1, 0, + FW_ISO_CONTEXT_MATCH_TAG1); if (err < 0) goto err_context; -- 1.8.3.2
next prev parent reply index Thread overview: 76+ messages / expand[flat|nested] mbox.gz Atom feed top [not found] <5316963F.1000206@sakamocchi.jp> 2014-03-05 6:14 ` [GIT PULL v2] Enhancement of support for Firewire devices Takashi Iwai 2014-03-05 11:00 ` Takashi Sakamoto 2014-03-05 11:09 ` Takashi Iwai 2014-03-05 11:23 ` Takashi Sakamoto 2014-03-05 10:47 ` [GIT PULL][PATCH 00/39 " Takashi Sakamoto 2014-03-05 10:47 ` [PATCH 01/39] firewire-lib: Rename functions, structure, member for AMDTP Takashi Sakamoto 2014-03-05 10:47 ` [PATCH 02/39] firewire-lib: Add macros instead of fixed value " Takashi Sakamoto 2014-03-05 10:47 ` [PATCH 03/39] firewire-lib: Add 'direction' member to 'amdtp_stream' structure Takashi Sakamoto 2014-03-05 10:47 ` [PATCH 04/39] firewire-lib: Split some codes into functions to reuse for both streams Takashi Sakamoto 2014-03-05 10:47 ` Takashi Sakamoto [this message] 2014-03-09 20:37 ` [PATCH 05/39] firewire-lib: Add support for AMDTP in-stream and PCM capture Clemens Ladisch 2014-03-10 3:55 ` Takashi Sakamoto 2014-03-12 2:00 ` Takashi Sakamoto 2014-03-14 13:50 ` Takashi Sakamoto 2014-03-05 10:47 ` [PATCH 06/39] firewire-lib: Add support for MIDI capture/playback Takashi Sakamoto 2014-03-09 20:48 ` Clemens Ladisch 2014-03-10 4:13 ` Takashi Sakamoto 2014-03-05 10:47 ` [PATCH 07/39] firewire-lib: Give syt value as parameter to handle_out_packet() Takashi Sakamoto 2014-03-05 10:47 ` [PATCH 08/39] firewire-lib: Add support for duplex streams synchronization in blocking mode Takashi Sakamoto 2014-03-09 20:55 ` Clemens Ladisch 2014-03-10 12:21 ` Takashi Sakamoto 2014-03-05 10:47 ` [PATCH 09/39] firewire-lib: Add sort function for transmitted packet Takashi Sakamoto 2014-03-09 21:07 ` Clemens Ladisch 2014-03-10 13:29 ` Takashi Sakamoto 2014-03-11 8:11 ` Clemens Ladisch 2014-03-12 1:23 ` Takashi Sakamoto 2014-03-12 7:21 ` Takashi Iwai 2014-03-05 10:47 ` [PATCH 10/39] firewire-lib: Add transfer delay to synchronized duplex streams Takashi Sakamoto 2014-03-09 21:13 ` Clemens Ladisch 2014-03-10 13:43 ` Takashi Sakamoto 2014-03-11 8:13 ` Clemens Ladisch 2014-03-05 10:47 ` [PATCH 11/39] firewire-lib: Add support for channel mapping Takashi Sakamoto 2014-03-09 21:20 ` Clemens Ladisch 2014-03-10 12:28 ` Takashi Sakamoto 2014-03-10 12:58 ` Takashi Sakamoto 2014-03-11 8:23 ` Clemens Ladisch 2014-03-11 16:03 ` Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 12/39] firewire-lib: Rename macros, variables and functions for CMP Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 13/39] firewire-lib: Add 'direction' member to 'cmp_connection' structure Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 14/39] firewire-lib: Add handling output connection by CMP Takashi Sakamoto 2014-03-09 21:27 ` Clemens Ladisch 2014-03-10 12:30 ` Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 15/39] firewire-lib: Add a new function to check others' connection Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 16/39] firewire-lib: Add some AV/C general commands Takashi Sakamoto 2014-03-09 21:32 ` Clemens Ladisch 2014-03-10 12:46 ` Takashi Sakamoto 2014-03-14 14:10 ` Takashi Sakamoto 2014-03-14 22:18 ` Clemens Ladisch 2014-03-05 10:48 ` [PATCH 17/39] firewire-lib: Add quirks for Fireworks Takashi Sakamoto 2014-03-09 21:39 ` Clemens Ladisch 2014-03-10 12:40 ` Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 18/39] firewire-lib: Add a fallback at RCODE_CANCELLED Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 19/39] fireworks: Add skelton for Fireworks based devices Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 20/39] fireworks: Add transaction and some commands Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 21/39] fireworks: Add connection and stream management Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 22/39] fireworks: Add proc interface for debugging purpose Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 23/39] fireworks: Add MIDI interface Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 24/39] fireworks: Add PCM interface Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 25/39] fireworks: Add hwdep interface Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 26/39] fireworks: Add command/response functionality into " Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 27/39] bebob: Add skelton for BeBoB based devices Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 28/39] bebob: Add commands and connections/streams management Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 29/39] bebob: Add proc interface for debugging purpose Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 30/39] bebob: Add MIDI interface Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 31/39] bebob: Add PCM interface Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 32/39] bebob: Add hwdep interface Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 33/39] bebob: Prepare for device specific operations Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 34/39] bebob: Add support for Terratec PHASE, EWS series and Aureon Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 35/39] bebob: Add support for Yamaha GO series Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 36/39] bebob: Add support for Focusrite Saffire/SaffirePro series Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 37/39] bebob: Add support for M-Audio usual Firewire series Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 38/39] bebob: Add support for M-Audio special " Takashi Sakamoto 2014-03-05 10:48 ` [PATCH 39/39] bebob: Send a cue to load firmware for M-Audio " Takashi Sakamoto 2014-03-07 11:44 ` [GIT PULL v2] Enhancement of support for Firewire devices Takashi Iwai 2014-03-07 14:46 ` Clemens Ladisch 2014-02-28 3:27 [GIT PULL][PATCH 00/39] " Takashi Sakamoto 2014-02-28 3:27 ` [PATCH 05/39] firewire-lib: Add support for AMDTP in-stream and PCM capture Takashi Sakamoto
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1394016507-15761-6-git-send-email-o-takashi@sakamocchi.jp \ --to=o-takashi@sakamocchi.jp \ --cc=alsa-devel@alsa-project.org \ --cc=clemens@ladisch.de \ --cc=ffado-devel@lists.sf.net \ --cc=perex@perex.cz \ --cc=tiwai@suse.de \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Alsa-Devel Archive on lore.kernel.org Archives are clonable: git clone --mirror https://lore.kernel.org/alsa-devel/0 alsa-devel/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 alsa-devel alsa-devel/ https://lore.kernel.org/alsa-devel \ alsa-devel@alsa-project.org public-inbox-index alsa-devel Example config snippet for mirrors Newsgroup available over NNTP: nntp://nntp.lore.kernel.org/org.alsa-project.alsa-devel AGPL code for this site: git clone https://public-inbox.org/public-inbox.git