]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/firewire/tascam/amdtp-tascam.c
Merge remote-tracking branch 'sound-current/for-linus'
[karo-tx-linux.git] / sound / firewire / tascam / amdtp-tascam.c
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         void (*transfer_samples)(struct amdtp_stream *s,
19                                  struct snd_pcm_substream *pcm,
20                                  __be32 *buffer, unsigned int frames);
21 };
22
23 int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate)
24 {
25         struct amdtp_tscm *p = s->protocol;
26         unsigned int data_channels;
27
28         if (amdtp_stream_running(s))
29                 return -EBUSY;
30
31         data_channels = p->pcm_channels;
32
33         /* Packets in in-stream have extra 2 data channels. */
34         if (s->direction == AMDTP_IN_STREAM)
35                 data_channels += 2;
36
37         return amdtp_stream_set_parameters(s, rate, data_channels);
38 }
39
40 static void write_pcm_s32(struct amdtp_stream *s,
41                           struct snd_pcm_substream *pcm,
42                           __be32 *buffer, unsigned int frames)
43 {
44         struct amdtp_tscm *p = s->protocol;
45         struct snd_pcm_runtime *runtime = pcm->runtime;
46         unsigned int channels, remaining_frames, i, c;
47         const u32 *src;
48
49         channels = p->pcm_channels;
50         src = (void *)runtime->dma_area +
51                         frames_to_bytes(runtime, s->pcm_buffer_pointer);
52         remaining_frames = runtime->buffer_size - s->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 write_pcm_s16(struct amdtp_stream *s,
66                           struct snd_pcm_substream *pcm,
67                           __be32 *buffer, unsigned int frames)
68 {
69         struct amdtp_tscm *p = s->protocol;
70         struct snd_pcm_runtime *runtime = pcm->runtime;
71         unsigned int channels, remaining_frames, i, c;
72         const u16 *src;
73
74         channels = p->pcm_channels;
75         src = (void *)runtime->dma_area +
76                         frames_to_bytes(runtime, s->pcm_buffer_pointer);
77         remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
78
79         for (i = 0; i < frames; ++i) {
80                 for (c = 0; c < channels; ++c) {
81                         buffer[c] = cpu_to_be32(*src << 16);
82                         src++;
83                 }
84                 buffer += s->data_block_quadlets;
85                 if (--remaining_frames == 0)
86                         src = (void *)runtime->dma_area;
87         }
88 }
89
90 static void read_pcm_s32(struct amdtp_stream *s,
91                          struct snd_pcm_substream *pcm,
92                          __be32 *buffer, unsigned int frames)
93 {
94         struct amdtp_tscm *p = s->protocol;
95         struct snd_pcm_runtime *runtime = pcm->runtime;
96         unsigned int channels, remaining_frames, i, c;
97         u32 *dst;
98
99         channels = p->pcm_channels;
100         dst  = (void *)runtime->dma_area +
101                         frames_to_bytes(runtime, s->pcm_buffer_pointer);
102         remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
103
104         /* The first data channel is for event counter. */
105         buffer += 1;
106
107         for (i = 0; i < frames; ++i) {
108                 for (c = 0; c < channels; ++c) {
109                         *dst = be32_to_cpu(buffer[c]);
110                         dst++;
111                 }
112                 buffer += s->data_block_quadlets;
113                 if (--remaining_frames == 0)
114                         dst = (void *)runtime->dma_area;
115         }
116 }
117
118 static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer,
119                               unsigned int data_blocks)
120 {
121         struct amdtp_tscm *p = s->protocol;
122         unsigned int channels, i, c;
123
124         channels = p->pcm_channels;
125
126         for (i = 0; i < data_blocks; ++i) {
127                 for (c = 0; c < channels; ++c)
128                         buffer[c] = 0x00000000;
129                 buffer += s->data_block_quadlets;
130         }
131 }
132
133 int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s,
134                                       struct snd_pcm_runtime *runtime)
135 {
136         int err;
137
138         /*
139          * Our implementation allows this protocol to deliver 24 bit sample in
140          * 32bit data channel.
141          */
142         err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
143         if (err < 0)
144                 return err;
145
146         return amdtp_stream_add_pcm_hw_constraints(s, runtime);
147 }
148
149 void amdtp_tscm_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
150 {
151         struct amdtp_tscm *p = s->protocol;
152
153         if (WARN_ON(amdtp_stream_pcm_running(s)))
154                 return;
155
156         switch (format) {
157         default:
158                 WARN_ON(1);
159                 /* fall through */
160         case SNDRV_PCM_FORMAT_S16:
161                 if (s->direction == AMDTP_OUT_STREAM) {
162                         p->transfer_samples = write_pcm_s16;
163                         break;
164                 }
165                 WARN_ON(1);
166                 /* fall through */
167         case SNDRV_PCM_FORMAT_S32:
168                 if (s->direction == AMDTP_OUT_STREAM)
169                         p->transfer_samples = write_pcm_s32;
170                 else
171                         p->transfer_samples = read_pcm_s32;
172                 break;
173         }
174 }
175
176 static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
177                                            __be32 *buffer,
178                                            unsigned int data_blocks,
179                                            unsigned int *syt)
180 {
181         struct amdtp_tscm *p = (struct amdtp_tscm *)s->protocol;
182         struct snd_pcm_substream *pcm;
183
184         pcm = ACCESS_ONCE(s->pcm);
185         if (data_blocks > 0 && pcm)
186                 p->transfer_samples(s, pcm, buffer, data_blocks);
187
188         /* A place holder for control messages. */
189
190         return data_blocks;
191 }
192
193 static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
194                                            __be32 *buffer,
195                                            unsigned int data_blocks,
196                                            unsigned int *syt)
197 {
198         struct amdtp_tscm *p = (struct amdtp_tscm *)s->protocol;
199         struct snd_pcm_substream *pcm;
200
201         /* This field is not used. */
202         *syt = 0x0000;
203
204         pcm = ACCESS_ONCE(s->pcm);
205         if (pcm)
206                 p->transfer_samples(s, pcm, buffer, data_blocks);
207         else
208                 write_pcm_silence(s, buffer, data_blocks);
209
210         return data_blocks;
211 }
212
213 int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
214                     enum amdtp_stream_direction dir, unsigned int pcm_channels)
215 {
216         amdtp_stream_process_data_blocks_t process_data_blocks;
217         struct amdtp_tscm *p;
218         unsigned int fmt;
219         int err;
220
221         if (dir == AMDTP_IN_STREAM) {
222                 fmt = AMDTP_FMT_TSCM_TX;
223                 process_data_blocks = process_tx_data_blocks;
224         } else {
225                 fmt = AMDTP_FMT_TSCM_RX;
226                 process_data_blocks = process_rx_data_blocks;
227         }
228
229         err = amdtp_stream_init(s, unit, dir,
230                                 CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK, fmt,
231                                 process_data_blocks, sizeof(struct amdtp_tscm));
232         if (err < 0)
233                 return 0;
234
235         /* Use fixed value for FDF field. */
236         s->fdf = 0x00;
237
238         /* This protocol uses fixed number of data channels for PCM samples. */
239         p = s->protocol;
240         p->pcm_channels = pcm_channels;
241
242         return 0;
243 }