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