amdtp-tascam.c (6451B)
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 14struct amdtp_tscm { 15 unsigned int pcm_channels; 16}; 17 18int 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); 33} 34 35static 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 65static 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 98static 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 113int 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 129static 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 179static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, 180 const struct pkt_desc *descs, 181 unsigned int packets, 182 struct snd_pcm_substream *pcm) 183{ 184 unsigned int pcm_frames = 0; 185 int i; 186 187 for (i = 0; i < packets; ++i) { 188 const struct pkt_desc *desc = descs + i; 189 __be32 *buf = desc->ctx_payload; 190 unsigned int data_blocks = desc->data_blocks; 191 192 if (pcm) { 193 read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 194 pcm_frames += data_blocks; 195 } 196 197 read_status_messages(s, buf, data_blocks); 198 } 199 200 return pcm_frames; 201} 202 203static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, 204 const struct pkt_desc *descs, 205 unsigned int packets, 206 struct snd_pcm_substream *pcm) 207{ 208 unsigned int pcm_frames = 0; 209 int i; 210 211 for (i = 0; i < packets; ++i) { 212 const struct pkt_desc *desc = descs + i; 213 __be32 *buf = desc->ctx_payload; 214 unsigned int data_blocks = desc->data_blocks; 215 216 if (pcm) { 217 write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 218 pcm_frames += data_blocks; 219 } else { 220 write_pcm_silence(s, buf, data_blocks); 221 } 222 } 223 224 return pcm_frames; 225} 226 227int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, 228 enum amdtp_stream_direction dir, unsigned int pcm_channels) 229{ 230 amdtp_stream_process_ctx_payloads_t process_ctx_payloads; 231 unsigned int flags = CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK | CIP_UNAWARE_SYT; 232 struct amdtp_tscm *p; 233 unsigned int fmt; 234 int err; 235 236 if (dir == AMDTP_IN_STREAM) { 237 fmt = AMDTP_FMT_TSCM_TX; 238 process_ctx_payloads = process_ir_ctx_payloads; 239 } else { 240 fmt = AMDTP_FMT_TSCM_RX; 241 process_ctx_payloads = process_it_ctx_payloads; 242 } 243 244 err = amdtp_stream_init(s, unit, dir, flags, fmt, 245 process_ctx_payloads, sizeof(struct amdtp_tscm)); 246 if (err < 0) 247 return 0; 248 249 if (dir == AMDTP_OUT_STREAM) { 250 // Use fixed value for FDF field. 251 s->ctx_data.rx.fdf = 0x00; 252 } 253 254 /* This protocol uses fixed number of data channels for PCM samples. */ 255 p = s->protocol; 256 p->pcm_channels = pcm_channels; 257 258 return 0; 259}