linux/sound/firewire/tascam/amdtp-tascam.c
<<
>>
Prefs
   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}
 260