linux/sound/firewire/tascam/amdtp-tascam.c
<<
>>
Prefs
   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
  15struct amdtp_tscm {
  16        unsigned int pcm_channels;
  17};
  18
  19int 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
  36static 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
  61static 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
  89static 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
 104int 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
 120static 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
 136static 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
 155int 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