1 /* 2 * amdtp-tascam.c - a part of driver for TASCAM FireWire series 3 * 4 * Copyright (c) 2015 Takashi Sakamoto 5 * 6 * Licensed under the terms of the GNU General Public License, version 2. 7 */ 8 9 #include <sound/pcm.h> 10 #include "tascam.h" 11 12 #define AMDTP_FMT_TSCM_TX 0x1e 13 #define AMDTP_FMT_TSCM_RX 0x3e 14 15 struct amdtp_tscm { 16 unsigned int pcm_channels; 17 }; 18 19 int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate) 20 { 21 struct amdtp_tscm *p = s->protocol; 22 unsigned int data_channels; 23 24 if (amdtp_stream_running(s)) 25 return -EBUSY; 26 27 data_channels = p->pcm_channels; 28 29 /* Packets in in-stream have extra 2 data channels. */ 30 if (s->direction == AMDTP_IN_STREAM) 31 data_channels += 2; 32 33 return amdtp_stream_set_parameters(s, rate, data_channels); 34 } 35 36 static void write_pcm_s32(struct amdtp_stream *s, 37 struct snd_pcm_substream *pcm, 38 __be32 *buffer, unsigned int frames) 39 { 40 struct amdtp_tscm *p = s->protocol; 41 struct snd_pcm_runtime *runtime = pcm->runtime; 42 unsigned int channels, remaining_frames, i, c; 43 const u32 *src; 44 45 channels = p->pcm_channels; 46 src = (void *)runtime->dma_area + 47 frames_to_bytes(runtime, s->pcm_buffer_pointer); 48 remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; 49 50 for (i = 0; i < frames; ++i) { 51 for (c = 0; c < channels; ++c) { 52 buffer[c] = cpu_to_be32(*src); 53 src++; 54 } 55 buffer += s->data_block_quadlets; 56 if (--remaining_frames == 0) 57 src = (void *)runtime->dma_area; 58 } 59 } 60 61 static void read_pcm_s32(struct amdtp_stream *s, 62 struct snd_pcm_substream *pcm, 63 __be32 *buffer, unsigned int frames) 64 { 65 struct amdtp_tscm *p = s->protocol; 66 struct snd_pcm_runtime *runtime = pcm->runtime; 67 unsigned int channels, remaining_frames, i, c; 68 u32 *dst; 69 70 channels = p->pcm_channels; 71 dst = (void *)runtime->dma_area + 72 frames_to_bytes(runtime, s->pcm_buffer_pointer); 73 remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; 74 75 /* The first data channel is for event counter. */ 76 buffer += 1; 77 78 for (i = 0; i < frames; ++i) { 79 for (c = 0; c < channels; ++c) { 80 *dst = be32_to_cpu(buffer[c]); 81 dst++; 82 } 83 buffer += s->data_block_quadlets; 84 if (--remaining_frames == 0) 85 dst = (void *)runtime->dma_area; 86 } 87 } 88 89 static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer, 90 unsigned int data_blocks) 91 { 92 struct amdtp_tscm *p = s->protocol; 93 unsigned int channels, i, c; 94 95 channels = p->pcm_channels; 96 97 for (i = 0; i < data_blocks; ++i) { 98 for (c = 0; c < channels; ++c) 99 buffer[c] = 0x00000000; 100 buffer += s->data_block_quadlets; 101 } 102 } 103 104 int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s, 105 struct snd_pcm_runtime *runtime) 106 { 107 int err; 108 109 /* 110 * Our implementation allows this protocol to deliver 24 bit sample in 111 * 32bit data channel. 112 */ 113 err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 114 if (err < 0) 115 return err; 116 117 return amdtp_stream_add_pcm_hw_constraints(s, runtime); 118 } 119 120 static unsigned int process_tx_data_blocks(struct amdtp_stream *s, 121 __be32 *buffer, 122 unsigned int data_blocks, 123 unsigned int *syt) 124 { 125 struct snd_pcm_substream *pcm; 126 127 pcm = ACCESS_ONCE(s->pcm); 128 if (data_blocks > 0 && pcm) 129 read_pcm_s32(s, pcm, buffer, data_blocks); 130 131 /* A place holder for control messages. */ 132 133 return data_blocks; 134 } 135 136 static unsigned int process_rx_data_blocks(struct amdtp_stream *s, 137 __be32 *buffer, 138 unsigned int data_blocks, 139 unsigned int *syt) 140 { 141 struct snd_pcm_substream *pcm; 142 143 /* This field is not used. */ 144 *syt = 0x0000; 145 146 pcm = ACCESS_ONCE(s->pcm); 147 if (pcm) 148 write_pcm_s32(s, pcm, buffer, data_blocks); 149 else 150 write_pcm_silence(s, buffer, data_blocks); 151 152 return data_blocks; 153 } 154 155 int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, 156 enum amdtp_stream_direction dir, unsigned int pcm_channels) 157 { 158 amdtp_stream_process_data_blocks_t process_data_blocks; 159 struct amdtp_tscm *p; 160 unsigned int fmt; 161 int err; 162 163 if (dir == AMDTP_IN_STREAM) { 164 fmt = AMDTP_FMT_TSCM_TX; 165 process_data_blocks = process_tx_data_blocks; 166 } else { 167 fmt = AMDTP_FMT_TSCM_RX; 168 process_data_blocks = process_rx_data_blocks; 169 } 170 171 err = amdtp_stream_init(s, unit, dir, 172 CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK, fmt, 173 process_data_blocks, sizeof(struct amdtp_tscm)); 174 if (err < 0) 175 return 0; 176 177 /* Use fixed value for FDF field. */ 178 s->fdf = 0x00; 179 180 /* This protocol uses fixed number of data channels for PCM samples. */ 181 p = s->protocol; 182 p->pcm_channels = pcm_channels; 183 184 return 0; 185 } 186