1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * amdtp-tascam.c - a part of driver for TASCAM FireWire series 4 * 5 * Copyright (c) 2015 Takashi Sakamoto 6 */ 7 8 #include <sound/pcm.h> 9 #include "tascam.h" 10 11 #define AMDTP_FMT_TSCM_TX 0x1e 12 #define AMDTP_FMT_TSCM_RX 0x3e 13 14 struct amdtp_tscm { 15 unsigned int pcm_channels; 16 }; 17 18 int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate) 19 { 20 struct amdtp_tscm *p = s->protocol; 21 unsigned int data_channels; 22 23 if (amdtp_stream_running(s)) 24 return -EBUSY; 25 26 data_channels = p->pcm_channels; 27 28 /* Packets in in-stream have extra 2 data channels. */ 29 if (s->direction == AMDTP_IN_STREAM) 30 data_channels += 2; 31 32 return amdtp_stream_set_parameters(s, rate, data_channels, 1); 33 } 34 35 static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 36 __be32 *buffer, unsigned int frames, 37 unsigned int pcm_frames) 38 { 39 struct amdtp_tscm *p = s->protocol; 40 unsigned int channels = p->pcm_channels; 41 struct snd_pcm_runtime *runtime = pcm->runtime; 42 unsigned int pcm_buffer_pointer; 43 int remaining_frames; 44 const u32 *src; 45 int i, c; 46 47 pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 48 pcm_buffer_pointer %= runtime->buffer_size; 49 50 src = (void *)runtime->dma_area + 51 frames_to_bytes(runtime, pcm_buffer_pointer); 52 remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 53 54 for (i = 0; i < frames; ++i) { 55 for (c = 0; c < channels; ++c) { 56 buffer[c] = cpu_to_be32(*src); 57 src++; 58 } 59 buffer += s->data_block_quadlets; 60 if (--remaining_frames == 0) 61 src = (void *)runtime->dma_area; 62 } 63 } 64 65 static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 66 __be32 *buffer, unsigned int frames, 67 unsigned int pcm_frames) 68 { 69 struct amdtp_tscm *p = s->protocol; 70 unsigned int channels = p->pcm_channels; 71 struct snd_pcm_runtime *runtime = pcm->runtime; 72 unsigned int pcm_buffer_pointer; 73 int remaining_frames; 74 u32 *dst; 75 int i, c; 76 77 pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 78 pcm_buffer_pointer %= runtime->buffer_size; 79 80 dst = (void *)runtime->dma_area + 81 frames_to_bytes(runtime, pcm_buffer_pointer); 82 remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 83 84 /* The first data channel is for event counter. */ 85 buffer += 1; 86 87 for (i = 0; i < frames; ++i) { 88 for (c = 0; c < channels; ++c) { 89 *dst = be32_to_cpu(buffer[c]); 90 dst++; 91 } 92 buffer += s->data_block_quadlets; 93 if (--remaining_frames == 0) 94 dst = (void *)runtime->dma_area; 95 } 96 } 97 98 static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer, 99 unsigned int data_blocks) 100 { 101 struct amdtp_tscm *p = s->protocol; 102 unsigned int channels, i, c; 103 104 channels = p->pcm_channels; 105 106 for (i = 0; i < data_blocks; ++i) { 107 for (c = 0; c < channels; ++c) 108 buffer[c] = 0x00000000; 109 buffer += s->data_block_quadlets; 110 } 111 } 112 113 int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s, 114 struct snd_pcm_runtime *runtime) 115 { 116 int err; 117 118 /* 119 * Our implementation allows this protocol to deliver 24 bit sample in 120 * 32bit data channel. 121 */ 122 err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 123 if (err < 0) 124 return err; 125 126 return amdtp_stream_add_pcm_hw_constraints(s, runtime); 127 } 128 129 static void read_status_messages(struct amdtp_stream *s, 130 __be32 *buffer, unsigned int data_blocks) 131 { 132 struct snd_tscm *tscm = container_of(s, struct snd_tscm, tx_stream); 133 bool used = READ_ONCE(tscm->hwdep->used); 134 int i; 135 136 for (i = 0; i < data_blocks; i++) { 137 unsigned int index; 138 __be32 before; 139 __be32 after; 140 141 index = be32_to_cpu(buffer[0]) % SNDRV_FIREWIRE_TASCAM_STATE_COUNT; 142 before = tscm->state[index]; 143 after = buffer[s->data_block_quadlets - 1]; 144 145 if (used && index > 4 && index < 16) { 146 __be32 mask; 147 148 if (index == 5) 149 mask = cpu_to_be32(~0x0000ffff); 150 else if (index == 6) 151 mask = cpu_to_be32(~0x0000ffff); 152 else if (index == 8) 153 mask = cpu_to_be32(~0x000f0f00); 154 else 155 mask = cpu_to_be32(~0x00000000); 156 157 if ((before ^ after) & mask) { 158 struct snd_firewire_tascam_change *entry = 159 &tscm->queue[tscm->push_pos]; 160 unsigned long flag; 161 162 spin_lock_irqsave(&tscm->lock, flag); 163 entry->index = index; 164 entry->before = before; 165 entry->after = after; 166 if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT) 167 tscm->push_pos = 0; 168 spin_unlock_irqrestore(&tscm->lock, flag); 169 170 wake_up(&tscm->hwdep_wait); 171 } 172 } 173 174 tscm->state[index] = after; 175 buffer += s->data_block_quadlets; 176 } 177 } 178 179 static void process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, 180 unsigned int count, struct snd_pcm_substream *pcm) 181 { 182 unsigned int pcm_frames = 0; 183 int i; 184 185 for (i = 0; i < count; ++i) { 186 __be32 *buf = desc->ctx_payload; 187 unsigned int data_blocks = desc->data_blocks; 188 189 if (pcm) { 190 read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 191 pcm_frames += data_blocks; 192 } 193 194 read_status_messages(s, buf, data_blocks); 195 196 desc = amdtp_stream_next_packet_desc(s, desc); 197 } 198 } 199 200 static void process_it_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, 201 unsigned int count, struct snd_pcm_substream *pcm) 202 { 203 unsigned int pcm_frames = 0; 204 int i; 205 206 for (i = 0; i < count; ++i) { 207 __be32 *buf = desc->ctx_payload; 208 unsigned int data_blocks = desc->data_blocks; 209 210 if (pcm) { 211 write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 212 pcm_frames += data_blocks; 213 } else { 214 write_pcm_silence(s, buf, data_blocks); 215 } 216 217 desc = amdtp_stream_next_packet_desc(s, desc); 218 } 219 } 220 221 int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, 222 enum amdtp_stream_direction dir, unsigned int pcm_channels) 223 { 224 amdtp_stream_process_ctx_payloads_t process_ctx_payloads; 225 unsigned int flags = CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK | CIP_UNAWARE_SYT; 226 struct amdtp_tscm *p; 227 unsigned int fmt; 228 int err; 229 230 if (dir == AMDTP_IN_STREAM) { 231 fmt = AMDTP_FMT_TSCM_TX; 232 process_ctx_payloads = process_ir_ctx_payloads; 233 } else { 234 fmt = AMDTP_FMT_TSCM_RX; 235 process_ctx_payloads = process_it_ctx_payloads; 236 } 237 238 err = amdtp_stream_init(s, unit, dir, flags, fmt, 239 process_ctx_payloads, sizeof(struct amdtp_tscm)); 240 if (err < 0) 241 return 0; 242 243 if (dir == AMDTP_OUT_STREAM) { 244 // Use fixed value for FDF field. 245 s->ctx_data.rx.fdf = 0x00; 246 } 247 248 /* This protocol uses fixed number of data channels for PCM samples. */ 249 p = s->protocol; 250 p->pcm_channels = pcm_channels; 251 252 return 0; 253 } 254
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.