diff options
Diffstat (limited to 'sound/firewire/amdtp-am824.c')
| -rw-r--r-- | sound/firewire/amdtp-am824.c | 170 |
1 files changed, 96 insertions, 74 deletions
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 4210e5c6262e..3660c312bf33 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AM824 format in Audio and Music Data Transmission Protocol (IEC 61883-6) * * Copyright (c) Clemens Ladisch <clemens@ladisch.de> * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp> - * - * Licensed under the terms of the GNU General Public License, version 2. */ #include <linux/slab.h> @@ -37,8 +36,6 @@ struct amdtp_am824 { u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM]; u8 midi_position; - - unsigned int frame_multiplier; }; /** @@ -60,8 +57,8 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, { struct amdtp_am824 *p = s->protocol; unsigned int midi_channels; - unsigned int i; - int err; + unsigned int pcm_frame_multiplier; + int i, err; if (amdtp_stream_running(s)) return -EINVAL; @@ -78,25 +75,26 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)) return -EINVAL; - err = amdtp_stream_set_parameters(s, rate, - pcm_channels + midi_channels); - if (err < 0) - return err; - - s->fdf = AMDTP_FDF_AM824 | s->sfc; - - p->pcm_channels = pcm_channels; - p->midi_ports = midi_ports; - /* * In IEC 61883-6, one data block represents one event. In ALSA, one * event equals to one PCM frame. But Dice has a quirk at higher * sampling rate to transfer two PCM frames in one data block. */ if (double_pcm_frames) - p->frame_multiplier = 2; + pcm_frame_multiplier = 2; else - p->frame_multiplier = 1; + pcm_frame_multiplier = 1; + + err = amdtp_stream_set_parameters(s, rate, pcm_channels + midi_channels, + pcm_frame_multiplier); + if (err < 0) + return err; + + if (s->direction == AMDTP_OUT_STREAM) + s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc; + + p->pcm_channels = pcm_channels; + p->midi_ports = midi_ports; /* init the position map for PCM and MIDI channels */ for (i = 0; i < pcm_channels; i++) @@ -147,19 +145,24 @@ void amdtp_am824_set_midi_position(struct amdtp_stream *s, } EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position); -static void write_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) +static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_am824 *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; const u32 *src; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -173,19 +176,24 @@ static void write_pcm_s32(struct amdtp_stream *s, } } -static void read_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) +static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_am824 *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; u32 *dst; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; dst = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -285,7 +293,7 @@ static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port) } static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, - unsigned int frames) + unsigned int frames, unsigned int data_block_counter) { struct amdtp_am824 *p = s->protocol; unsigned int f, port; @@ -294,7 +302,7 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, for (f = 0; f < frames; f++) { b = (u8 *)&buffer[p->midi_position]; - port = (s->data_block_counter + f) % 8; + port = (data_block_counter + f) % 8; if (f < MAX_MIDI_RX_BLOCKS && midi_ratelimit_per_packet(s, port) && p->midi[port] != NULL && @@ -312,16 +320,20 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, } } -static void read_midi_messages(struct amdtp_stream *s, - __be32 *buffer, unsigned int frames) +static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, + unsigned int frames, unsigned int data_block_counter) { struct amdtp_am824 *p = s->protocol; - unsigned int f, port; int len; u8 *b; + int f; for (f = 0; f < frames; f++) { - port = (s->data_block_counter + f) % 8; + unsigned int port = f; + + if (!(s->flags & CIP_UNALIGHED_DBC)) + port += data_block_counter; + port %= 8; b = (u8 *)&buffer[p->midi_position]; len = b[0] - 0x80; @@ -332,45 +344,56 @@ static void read_midi_messages(struct amdtp_stream *s, } } -static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks, unsigned int *syt) +static void process_it_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, + unsigned int count, struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); - unsigned int pcm_frames; - - if (pcm) { - write_pcm_s32(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks * p->frame_multiplier; - } else { - write_pcm_silence(s, buffer, data_blocks); - pcm_frames = 0; - } + unsigned int pcm_frames = 0; + int i; - if (p->midi_ports) - write_midi_messages(s, buffer, data_blocks); + for (i = 0; i < count; ++i) { + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - return pcm_frames; + if (pcm) { + write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks * s->pcm_frame_multiplier; + } else { + write_pcm_silence(s, buf, data_blocks); + } + + if (p->midi_ports) { + write_midi_messages(s, buf, data_blocks, + desc->data_block_counter); + } + + desc = amdtp_stream_next_packet_desc(s, desc); + } } -static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks, unsigned int *syt) +static void process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, + unsigned int count, struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); - unsigned int pcm_frames; - - if (pcm) { - read_pcm_s32(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks * p->frame_multiplier; - } else { - pcm_frames = 0; - } + unsigned int pcm_frames = 0; + int i; + + for (i = 0; i < count; ++i) { + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - if (p->midi_ports) - read_midi_messages(s, buffer, data_blocks); + if (pcm) { + read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks * s->pcm_frame_multiplier; + } + + if (p->midi_ports) { + read_midi_messages(s, buf, data_blocks, + desc->data_block_counter); + } - return pcm_frames; + desc = amdtp_stream_next_packet_desc(s, desc); + } } /** @@ -379,20 +402,19 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffe * @s: the AMDTP stream to initialize * @unit: the target of the stream * @dir: the direction of stream - * @flags: the packet transmission method to use + * @flags: the details of the streaming protocol consist of cip_flags enumeration-constants. */ int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, - enum amdtp_stream_direction dir, enum cip_flags flags) + enum amdtp_stream_direction dir, unsigned int flags) { - amdtp_stream_process_data_blocks_t process_data_blocks; + amdtp_stream_process_ctx_payloads_t process_ctx_payloads; if (dir == AMDTP_IN_STREAM) - process_data_blocks = process_tx_data_blocks; + process_ctx_payloads = process_ir_ctx_payloads; else - process_data_blocks = process_rx_data_blocks; + process_ctx_payloads = process_it_ctx_payloads; return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, - process_data_blocks, - sizeof(struct amdtp_am824)); + process_ctx_payloads, sizeof(struct amdtp_am824)); } EXPORT_SYMBOL_GPL(amdtp_am824_init); |
