]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/firewire/digi00x/amdtp-dot.c
e6731d33c48037912f8ab428ddfbe67ef82d0105
[karo-tx-linux.git] / sound / firewire / digi00x / amdtp-dot.c
1 /*
2  * amdtp-dot.c - a part of driver for Digidesign Digi 002/003 family
3  *
4  * Copyright (c) 2014-2015 Takashi Sakamoto
5  * Copyright (C) 2012 Robin Gareus <robin@gareus.org>
6  * Copyright (C) 2012 Damien Zammit <damien@zamaudio.com>
7  *
8  * Licensed under the terms of the GNU General Public License, version 2.
9  */
10
11 #include <sound/pcm.h>
12 #include "digi00x.h"
13
14 #define CIP_FMT_AM              0x10
15
16 /* 'Clock-based rate control mode' is just supported. */
17 #define AMDTP_FDF_AM824         0x00
18
19 /*
20  * The double-oh-three algorithm was discovered by Robin Gareus and Damien
21  * Zammit in 2012, with reverse-engineering for Digi 003 Rack.
22  */
23 struct dot_state {
24         __u8 carry;
25         __u8 idx;
26         unsigned int off;
27 };
28
29 struct amdtp_dot {
30         unsigned int pcm_channels;
31         struct dot_state state;
32
33         unsigned int midi_ports;
34
35         void (*transfer_samples)(struct amdtp_stream *s,
36                                  struct snd_pcm_substream *pcm,
37                                  __be32 *buffer, unsigned int frames);
38 };
39
40 /*
41  * double-oh-three look up table
42  *
43  * @param idx index byte (audio-sample data) 0x00..0xff
44  * @param off channel offset shift
45  * @return salt to XOR with given data
46  */
47 #define BYTE_PER_SAMPLE (4)
48 #define MAGIC_DOT_BYTE (2)
49 #define MAGIC_BYTE_OFF(x) (((x) * BYTE_PER_SAMPLE) + MAGIC_DOT_BYTE)
50 static const __u8 dot_scrt(const __u8 idx, const unsigned int off)
51 {
52         /*
53          * the length of the added pattern only depends on the lower nibble
54          * of the last non-zero data
55          */
56         static const __u8 len[16] = {0, 1, 3, 5, 7, 9, 11, 13, 14,
57                                      12, 10, 8, 6, 4, 2, 0};
58
59         /*
60          * the lower nibble of the salt. Interleaved sequence.
61          * this is walked backwards according to len[]
62          */
63         static const __u8 nib[15] = {0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4,
64                                      0xc, 0x3, 0xd, 0x2, 0xe, 0x1, 0xf};
65
66         /* circular list for the salt's hi nibble. */
67         static const __u8 hir[15] = {0x0, 0x6, 0xf, 0x8, 0x7, 0x5, 0x3, 0x4,
68                                      0xc, 0xd, 0xe, 0x1, 0x2, 0xb, 0xa};
69
70         /*
71          * start offset for upper nibble mapping.
72          * note: 9 is /special/. In the case where the high nibble == 0x9,
73          * hir[] is not used and - coincidentally - the salt's hi nibble is
74          * 0x09 regardless of the offset.
75          */
76         static const __u8 hio[16] = {0, 11, 12, 6, 7, 5, 1, 4,
77                                      3, 0x00, 14, 13, 8, 9, 10, 2};
78
79         const __u8 ln = idx & 0xf;
80         const __u8 hn = (idx >> 4) & 0xf;
81         const __u8 hr = (hn == 0x9) ? 0x9 : hir[(hio[hn] + off) % 15];
82
83         if (len[ln] < off)
84                 return 0x00;
85
86         return ((nib[14 + off - len[ln]]) | (hr << 4));
87 }
88
89 static void dot_encode_step(struct dot_state *state, __be32 *const buffer)
90 {
91         __u8 * const data = (__u8 *) buffer;
92
93         if (data[MAGIC_DOT_BYTE] != 0x00) {
94                 state->off = 0;
95                 state->idx = data[MAGIC_DOT_BYTE] ^ state->carry;
96         }
97         data[MAGIC_DOT_BYTE] ^= state->carry;
98         state->carry = dot_scrt(state->idx, ++(state->off));
99 }
100
101 int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate,
102                              unsigned int pcm_channels, unsigned int midi_ports)
103 {
104         struct amdtp_dot *p = s->protocol;
105         int err;
106
107         if (amdtp_stream_running(s))
108                 return -EBUSY;
109
110         /*
111          * A first data channel is for MIDI conformant data channel, the rest is
112          * Multi Bit Linear Audio data channel.
113          */
114         err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1);
115         if (err < 0)
116                 return err;
117
118         s->fdf = AMDTP_FDF_AM824 | s->sfc;
119
120         p->pcm_channels = pcm_channels;
121         p->midi_ports = midi_ports;
122
123         return 0;
124 }
125
126 static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
127                           __be32 *buffer, unsigned int frames)
128 {
129         struct amdtp_dot *p = s->protocol;
130         struct snd_pcm_runtime *runtime = pcm->runtime;
131         unsigned int channels, remaining_frames, i, c;
132         const u32 *src;
133
134         channels = p->pcm_channels;
135         src = (void *)runtime->dma_area +
136                         frames_to_bytes(runtime, s->pcm_buffer_pointer);
137         remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
138
139         buffer++;
140         for (i = 0; i < frames; ++i) {
141                 for (c = 0; c < channels; ++c) {
142                         buffer[c] = cpu_to_be32((*src >> 8) | 0x40000000);
143                         dot_encode_step(&p->state, &buffer[c]);
144                         src++;
145                 }
146                 buffer += s->data_block_quadlets;
147                 if (--remaining_frames == 0)
148                         src = (void *)runtime->dma_area;
149         }
150 }
151
152 static void write_pcm_s16(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
153                           __be32 *buffer, unsigned int frames)
154 {
155         struct amdtp_dot *p = s->protocol;
156         struct snd_pcm_runtime *runtime = pcm->runtime;
157         unsigned int channels, remaining_frames, i, c;
158         const u16 *src;
159
160         channels = p->pcm_channels;
161         src = (void *)runtime->dma_area +
162                         frames_to_bytes(runtime, s->pcm_buffer_pointer);
163         remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
164
165         buffer++;
166         for (i = 0; i < frames; ++i) {
167                 for (c = 0; c < channels; ++c) {
168                         buffer[c] = cpu_to_be32((*src << 8) | 0x40000000);
169                         dot_encode_step(&p->state, &buffer[c]);
170                         src++;
171                 }
172                 buffer += s->data_block_quadlets;
173                 if (--remaining_frames == 0)
174                         src = (void *)runtime->dma_area;
175         }
176 }
177
178 static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
179                          __be32 *buffer, unsigned int frames)
180 {
181         struct amdtp_dot *p = s->protocol;
182         struct snd_pcm_runtime *runtime = pcm->runtime;
183         unsigned int channels, remaining_frames, i, c;
184         u32 *dst;
185
186         channels = p->pcm_channels;
187         dst  = (void *)runtime->dma_area +
188                         frames_to_bytes(runtime, s->pcm_buffer_pointer);
189         remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
190
191         buffer++;
192         for (i = 0; i < frames; ++i) {
193                 for (c = 0; c < channels; ++c) {
194                         *dst = be32_to_cpu(buffer[c]) << 8;
195                         dst++;
196                 }
197                 buffer += s->data_block_quadlets;
198                 if (--remaining_frames == 0)
199                         dst = (void *)runtime->dma_area;
200         }
201 }
202
203 static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer,
204                               unsigned int data_blocks)
205 {
206         struct amdtp_dot *p = s->protocol;
207         unsigned int channels, i, c;
208
209         channels = p->pcm_channels;
210
211         buffer++;
212         for (i = 0; i < data_blocks; ++i) {
213                 for (c = 0; c < channels; ++c)
214                         buffer[c] = cpu_to_be32(0x40000000);
215                 buffer += s->data_block_quadlets;
216         }
217 }
218
219 int amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s,
220                                      struct snd_pcm_runtime *runtime)
221 {
222         int err;
223
224         /* This protocol delivers 24 bit data in 32bit data channel. */
225         err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
226         if (err < 0)
227                 return err;
228
229         return amdtp_stream_add_pcm_hw_constraints(s, runtime);
230 }
231
232 void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
233 {
234         struct amdtp_dot *p = s->protocol;
235
236         if (WARN_ON(amdtp_stream_pcm_running(s)))
237                 return;
238
239         switch (format) {
240         default:
241                 WARN_ON(1);
242                 /* fall through */
243         case SNDRV_PCM_FORMAT_S16:
244                 if (s->direction == AMDTP_OUT_STREAM) {
245                         p->transfer_samples = write_pcm_s16;
246                         break;
247                 }
248                 WARN_ON(1);
249                 /* fall through */
250         case SNDRV_PCM_FORMAT_S32:
251                 if (s->direction == AMDTP_OUT_STREAM)
252                         p->transfer_samples = write_pcm_s32;
253                 else
254                         p->transfer_samples = read_pcm_s32;
255                 break;
256         }
257 }
258
259 static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
260                                            __be32 *buffer,
261                                            unsigned int data_blocks,
262                                            unsigned int *syt)
263 {
264         struct amdtp_dot *p = (struct amdtp_dot *)s->protocol;
265         struct snd_pcm_substream *pcm;
266         unsigned int pcm_frames;
267
268         pcm = ACCESS_ONCE(s->pcm);
269         if (pcm) {
270                 p->transfer_samples(s, pcm, buffer, data_blocks);
271                 pcm_frames = data_blocks;
272         } else {
273                 pcm_frames = 0;
274         }
275
276         /* A place holder for MIDI processing. */
277
278         return pcm_frames;
279 }
280
281 static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
282                                            __be32 *buffer,
283                                            unsigned int data_blocks,
284                                            unsigned int *syt)
285 {
286         struct amdtp_dot *p = (struct amdtp_dot *)s->protocol;
287         struct snd_pcm_substream *pcm;
288         unsigned int pcm_frames;
289
290         pcm = ACCESS_ONCE(s->pcm);
291         if (pcm) {
292                 p->transfer_samples(s, pcm, buffer, data_blocks);
293                 pcm_frames = data_blocks;
294         } else {
295                 write_pcm_silence(s, buffer, data_blocks);
296                 pcm_frames = 0;
297         }
298
299         /* A place holder for MIDI processing. */
300
301         return pcm_frames;
302 }
303
304 int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit,
305                  enum amdtp_stream_direction dir)
306 {
307         amdtp_stream_process_data_blocks_t process_data_blocks;
308         enum cip_flags flags;
309
310         /* Use different mode between incoming/outgoing. */
311         if (dir == AMDTP_IN_STREAM) {
312                 flags = CIP_NONBLOCKING | CIP_SKIP_INIT_DBC_CHECK;
313                 process_data_blocks = process_tx_data_blocks;
314         } else {
315                 flags = CIP_BLOCKING;
316                 process_data_blocks = process_rx_data_blocks;
317         }
318
319         return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
320                                  process_data_blocks, sizeof(struct amdtp_dot));
321 }
322
323 void amdtp_dot_reset(struct amdtp_stream *s)
324 {
325         struct amdtp_dot *p = s->protocol;
326
327         p->state.carry = 0x00;
328         p->state.idx = 0x00;
329         p->state.off = 0;
330 }