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 11 struct amdtp_ff { 12 unsigned int pcm_channels; 13 }; 14 15 int 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, 1); 28 } 29 30 static 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 60 static 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 90 static 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 103 int 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 115 static void process_it_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, 116 unsigned int count, struct snd_pcm_substream *pcm) 117 { 118 unsigned int pcm_frames = 0; 119 int i; 120 121 for (i = 0; i < count; ++i) { 122 __le32 *buf = (__le32 *)desc->ctx_payload; 123 unsigned int data_blocks = desc->data_blocks; 124 125 if (pcm) { 126 write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 127 pcm_frames += data_blocks; 128 } else { 129 write_pcm_silence(s, buf, data_blocks); 130 } 131 132 desc = amdtp_stream_next_packet_desc(s, desc); 133 } 134 } 135 136 static void process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, 137 unsigned int count, struct snd_pcm_substream *pcm) 138 { 139 unsigned int pcm_frames = 0; 140 int i; 141 142 for (i = 0; i < count; ++i) { 143 __le32 *buf = (__le32 *)desc->ctx_payload; 144 unsigned int data_blocks = desc->data_blocks; 145 146 if (pcm) { 147 read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 148 pcm_frames += data_blocks; 149 } 150 151 desc = amdtp_stream_next_packet_desc(s, desc); 152 } 153 } 154 155 int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit, 156 enum amdtp_stream_direction dir) 157 { 158 amdtp_stream_process_ctx_payloads_t process_ctx_payloads; 159 160 if (dir == AMDTP_IN_STREAM) 161 process_ctx_payloads = process_ir_ctx_payloads; 162 else 163 process_ctx_payloads = process_it_ctx_payloads; 164 165 return amdtp_stream_init(s, unit, dir, CIP_BLOCKING | CIP_UNAWARE_SYT | CIP_NO_HEADER, 0, 166 process_ctx_payloads, sizeof(struct amdtp_ff)); 167 } 168
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.