amdtp-ff.c (4411B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * amdtp-ff.c - a part of driver for RME Fireface series 4 * 5 * Copyright (c) 2015-2017 Takashi Sakamoto 6 */ 7 8#include <sound/pcm.h> 9#include "ff.h" 10 11struct amdtp_ff { 12 unsigned int pcm_channels; 13}; 14 15int amdtp_ff_set_parameters(struct amdtp_stream *s, unsigned int rate, 16 unsigned int pcm_channels) 17{ 18 struct amdtp_ff *p = s->protocol; 19 unsigned int data_channels; 20 21 if (amdtp_stream_running(s)) 22 return -EBUSY; 23 24 p->pcm_channels = pcm_channels; 25 data_channels = pcm_channels; 26 27 return amdtp_stream_set_parameters(s, rate, data_channels); 28} 29 30static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 31 __le32 *buffer, unsigned int frames, 32 unsigned int pcm_frames) 33{ 34 struct amdtp_ff *p = s->protocol; 35 unsigned int channels = p->pcm_channels; 36 struct snd_pcm_runtime *runtime = pcm->runtime; 37 unsigned int pcm_buffer_pointer; 38 int remaining_frames; 39 const u32 *src; 40 int i, c; 41 42 pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 43 pcm_buffer_pointer %= runtime->buffer_size; 44 45 src = (void *)runtime->dma_area + 46 frames_to_bytes(runtime, pcm_buffer_pointer); 47 remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 48 49 for (i = 0; i < frames; ++i) { 50 for (c = 0; c < channels; ++c) { 51 buffer[c] = cpu_to_le32(*src); 52 src++; 53 } 54 buffer += s->data_block_quadlets; 55 if (--remaining_frames == 0) 56 src = (void *)runtime->dma_area; 57 } 58} 59 60static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 61 __le32 *buffer, unsigned int frames, 62 unsigned int pcm_frames) 63{ 64 struct amdtp_ff *p = s->protocol; 65 unsigned int channels = p->pcm_channels; 66 struct snd_pcm_runtime *runtime = pcm->runtime; 67 unsigned int pcm_buffer_pointer; 68 int remaining_frames; 69 u32 *dst; 70 int i, c; 71 72 pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 73 pcm_buffer_pointer %= runtime->buffer_size; 74 75 dst = (void *)runtime->dma_area + 76 frames_to_bytes(runtime, pcm_buffer_pointer); 77 remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 78 79 for (i = 0; i < frames; ++i) { 80 for (c = 0; c < channels; ++c) { 81 *dst = le32_to_cpu(buffer[c]) & 0xffffff00; 82 dst++; 83 } 84 buffer += s->data_block_quadlets; 85 if (--remaining_frames == 0) 86 dst = (void *)runtime->dma_area; 87 } 88} 89 90static void write_pcm_silence(struct amdtp_stream *s, 91 __le32 *buffer, unsigned int frames) 92{ 93 struct amdtp_ff *p = s->protocol; 94 unsigned int i, c, channels = p->pcm_channels; 95 96 for (i = 0; i < frames; ++i) { 97 for (c = 0; c < channels; ++c) 98 buffer[c] = cpu_to_le32(0x00000000); 99 buffer += s->data_block_quadlets; 100 } 101} 102 103int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s, 104 struct snd_pcm_runtime *runtime) 105{ 106 int err; 107 108 err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 109 if (err < 0) 110 return err; 111 112 return amdtp_stream_add_pcm_hw_constraints(s, runtime); 113} 114 115static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, 116 const struct pkt_desc *descs, 117 unsigned int packets, 118 struct snd_pcm_substream *pcm) 119{ 120 unsigned int pcm_frames = 0; 121 int i; 122 123 for (i = 0; i < packets; ++i) { 124 const struct pkt_desc *desc = descs + i; 125 __le32 *buf = (__le32 *)desc->ctx_payload; 126 unsigned int data_blocks = desc->data_blocks; 127 128 if (pcm) { 129 write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 130 pcm_frames += data_blocks; 131 } else { 132 write_pcm_silence(s, buf, data_blocks); 133 } 134 } 135 136 return pcm_frames; 137} 138 139static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, 140 const struct pkt_desc *descs, 141 unsigned int packets, 142 struct snd_pcm_substream *pcm) 143{ 144 unsigned int pcm_frames = 0; 145 int i; 146 147 for (i = 0; i < packets; ++i) { 148 const struct pkt_desc *desc = descs + i; 149 __le32 *buf = (__le32 *)desc->ctx_payload; 150 unsigned int data_blocks = desc->data_blocks; 151 152 if (pcm) { 153 read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 154 pcm_frames += data_blocks; 155 } 156 } 157 158 return pcm_frames; 159} 160 161int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit, 162 enum amdtp_stream_direction dir) 163{ 164 amdtp_stream_process_ctx_payloads_t process_ctx_payloads; 165 166 if (dir == AMDTP_IN_STREAM) 167 process_ctx_payloads = process_ir_ctx_payloads; 168 else 169 process_ctx_payloads = process_it_ctx_payloads; 170 171 return amdtp_stream_init(s, unit, dir, CIP_BLOCKING | CIP_UNAWARE_SYT | CIP_NO_HEADER, 0, 172 process_ctx_payloads, sizeof(struct amdtp_ff)); 173}