linux/sound/firewire/fireface/amdtp-ff.c
<<
>>
Prefs
   1/*
   2 * amdtp-ff.c - a part of driver for RME Fireface series
   3 *
   4 * Copyright (c) 2015-2017 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 "ff.h"
  11
  12struct amdtp_ff {
  13        unsigned int pcm_channels;
  14};
  15
  16int amdtp_ff_set_parameters(struct amdtp_stream *s, unsigned int rate,
  17                            unsigned int pcm_channels)
  18{
  19        struct amdtp_ff *p = s->protocol;
  20        unsigned int data_channels;
  21
  22        if (amdtp_stream_running(s))
  23                return -EBUSY;
  24
  25        p->pcm_channels = pcm_channels;
  26        data_channels = pcm_channels;
  27
  28        return amdtp_stream_set_parameters(s, rate, data_channels);
  29}
  30
  31static void write_pcm_s32(struct amdtp_stream *s,
  32                          struct snd_pcm_substream *pcm,
  33                          __le32 *buffer, unsigned int frames)
  34{
  35        struct amdtp_ff *p = s->protocol;
  36        struct snd_pcm_runtime *runtime = pcm->runtime;
  37        unsigned int channels, remaining_frames, i, c;
  38        const u32 *src;
  39
  40        channels = p->pcm_channels;
  41        src = (void *)runtime->dma_area +
  42                        frames_to_bytes(runtime, s->pcm_buffer_pointer);
  43        remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
  44
  45        for (i = 0; i < frames; ++i) {
  46                for (c = 0; c < channels; ++c) {
  47                        buffer[c] = cpu_to_le32(*src);
  48                        src++;
  49                }
  50                buffer += s->data_block_quadlets;
  51                if (--remaining_frames == 0)
  52                        src = (void *)runtime->dma_area;
  53        }
  54}
  55
  56static void read_pcm_s32(struct amdtp_stream *s,
  57                         struct snd_pcm_substream *pcm,
  58                         __le32 *buffer, unsigned int frames)
  59{
  60        struct amdtp_ff *p = s->protocol;
  61        struct snd_pcm_runtime *runtime = pcm->runtime;
  62        unsigned int channels, remaining_frames, i, c;
  63        u32 *dst;
  64
  65        channels = p->pcm_channels;
  66        dst  = (void *)runtime->dma_area +
  67                        frames_to_bytes(runtime, s->pcm_buffer_pointer);
  68        remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
  69
  70        for (i = 0; i < frames; ++i) {
  71                for (c = 0; c < channels; ++c) {
  72                        *dst = le32_to_cpu(buffer[c]) & 0xffffff00;
  73                        dst++;
  74                }
  75                buffer += s->data_block_quadlets;
  76                if (--remaining_frames == 0)
  77                        dst = (void *)runtime->dma_area;
  78        }
  79}
  80
  81static void write_pcm_silence(struct amdtp_stream *s,
  82                              __le32 *buffer, unsigned int frames)
  83{
  84        struct amdtp_ff *p = s->protocol;
  85        unsigned int i, c, channels = p->pcm_channels;
  86
  87        for (i = 0; i < frames; ++i) {
  88                for (c = 0; c < channels; ++c)
  89                        buffer[c] = cpu_to_le32(0x00000000);
  90                buffer += s->data_block_quadlets;
  91        }
  92}
  93
  94int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s,
  95                                    struct snd_pcm_runtime *runtime)
  96{
  97        int err;
  98
  99        err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 100        if (err < 0)
 101                return err;
 102
 103        return amdtp_stream_add_pcm_hw_constraints(s, runtime);
 104}
 105
 106static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
 107                                           __be32 *buffer,
 108                                           unsigned int data_blocks,
 109                                           unsigned int *syt)
 110{
 111        struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
 112        unsigned int pcm_frames;
 113
 114        if (pcm) {
 115                write_pcm_s32(s, pcm, (__le32 *)buffer, data_blocks);
 116                pcm_frames = data_blocks;
 117        } else {
 118                write_pcm_silence(s, (__le32 *)buffer, data_blocks);
 119                pcm_frames = 0;
 120        }
 121
 122        return pcm_frames;
 123}
 124
 125static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
 126                                           __be32 *buffer,
 127                                           unsigned int data_blocks,
 128                                           unsigned int *syt)
 129{
 130        struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
 131        unsigned int pcm_frames;
 132
 133        if (pcm) {
 134                read_pcm_s32(s, pcm, (__le32 *)buffer, data_blocks);
 135                pcm_frames = data_blocks;
 136        } else {
 137                pcm_frames = 0;
 138        }
 139
 140        return pcm_frames;
 141}
 142
 143int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit,
 144                  enum amdtp_stream_direction dir)
 145{
 146        amdtp_stream_process_data_blocks_t process_data_blocks;
 147
 148        if (dir == AMDTP_IN_STREAM)
 149                process_data_blocks = process_tx_data_blocks;
 150        else
 151                process_data_blocks = process_rx_data_blocks;
 152
 153        return amdtp_stream_init(s, unit, dir, CIP_NO_HEADER, 0,
 154                                 process_data_blocks, sizeof(struct amdtp_ff));
 155}
 156