Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * amdtp-ff.c - a part of driver for RME Fireface series
0004  *
0005  * Copyright (c) 2015-2017 Takashi Sakamoto
0006  */
0007 
0008 #include <sound/pcm.h>
0009 #include "ff.h"
0010 
0011 struct amdtp_ff {
0012     unsigned int pcm_channels;
0013 };
0014 
0015 int amdtp_ff_set_parameters(struct amdtp_stream *s, unsigned int rate,
0016                 unsigned int pcm_channels)
0017 {
0018     struct amdtp_ff *p = s->protocol;
0019     unsigned int data_channels;
0020 
0021     if (amdtp_stream_running(s))
0022         return -EBUSY;
0023 
0024     p->pcm_channels = pcm_channels;
0025     data_channels = pcm_channels;
0026 
0027     return amdtp_stream_set_parameters(s, rate, data_channels);
0028 }
0029 
0030 static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
0031               __le32 *buffer, unsigned int frames,
0032               unsigned int pcm_frames)
0033 {
0034     struct amdtp_ff *p = s->protocol;
0035     unsigned int channels = p->pcm_channels;
0036     struct snd_pcm_runtime *runtime = pcm->runtime;
0037     unsigned int pcm_buffer_pointer;
0038     int remaining_frames;
0039     const u32 *src;
0040     int i, c;
0041 
0042     pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
0043     pcm_buffer_pointer %= runtime->buffer_size;
0044 
0045     src = (void *)runtime->dma_area +
0046                 frames_to_bytes(runtime, pcm_buffer_pointer);
0047     remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
0048 
0049     for (i = 0; i < frames; ++i) {
0050         for (c = 0; c < channels; ++c) {
0051             buffer[c] = cpu_to_le32(*src);
0052             src++;
0053         }
0054         buffer += s->data_block_quadlets;
0055         if (--remaining_frames == 0)
0056             src = (void *)runtime->dma_area;
0057     }
0058 }
0059 
0060 static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
0061              __le32 *buffer, unsigned int frames,
0062              unsigned int pcm_frames)
0063 {
0064     struct amdtp_ff *p = s->protocol;
0065     unsigned int channels = p->pcm_channels;
0066     struct snd_pcm_runtime *runtime = pcm->runtime;
0067     unsigned int pcm_buffer_pointer;
0068     int remaining_frames;
0069     u32 *dst;
0070     int i, c;
0071 
0072     pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
0073     pcm_buffer_pointer %= runtime->buffer_size;
0074 
0075     dst  = (void *)runtime->dma_area +
0076                 frames_to_bytes(runtime, pcm_buffer_pointer);
0077     remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
0078 
0079     for (i = 0; i < frames; ++i) {
0080         for (c = 0; c < channels; ++c) {
0081             *dst = le32_to_cpu(buffer[c]) & 0xffffff00;
0082             dst++;
0083         }
0084         buffer += s->data_block_quadlets;
0085         if (--remaining_frames == 0)
0086             dst = (void *)runtime->dma_area;
0087     }
0088 }
0089 
0090 static void write_pcm_silence(struct amdtp_stream *s,
0091                   __le32 *buffer, unsigned int frames)
0092 {
0093     struct amdtp_ff *p = s->protocol;
0094     unsigned int i, c, channels = p->pcm_channels;
0095 
0096     for (i = 0; i < frames; ++i) {
0097         for (c = 0; c < channels; ++c)
0098             buffer[c] = cpu_to_le32(0x00000000);
0099         buffer += s->data_block_quadlets;
0100     }
0101 }
0102 
0103 int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s,
0104                     struct snd_pcm_runtime *runtime)
0105 {
0106     int err;
0107 
0108     err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
0109     if (err < 0)
0110         return err;
0111 
0112     return amdtp_stream_add_pcm_hw_constraints(s, runtime);
0113 }
0114 
0115 static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
0116                        const struct pkt_desc *descs,
0117                        unsigned int packets,
0118                        struct snd_pcm_substream *pcm)
0119 {
0120     unsigned int pcm_frames = 0;
0121     int i;
0122 
0123     for (i = 0; i < packets; ++i) {
0124         const struct pkt_desc *desc = descs + i;
0125         __le32 *buf = (__le32 *)desc->ctx_payload;
0126         unsigned int data_blocks = desc->data_blocks;
0127 
0128         if (pcm) {
0129             write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
0130             pcm_frames += data_blocks;
0131         } else {
0132             write_pcm_silence(s, buf, data_blocks);
0133         }
0134     }
0135 
0136     return pcm_frames;
0137 }
0138 
0139 static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
0140                         const struct pkt_desc *descs,
0141                         unsigned int packets,
0142                         struct snd_pcm_substream *pcm)
0143 {
0144     unsigned int pcm_frames = 0;
0145     int i;
0146 
0147     for (i = 0; i < packets; ++i) {
0148         const struct pkt_desc *desc = descs + i;
0149         __le32 *buf = (__le32 *)desc->ctx_payload;
0150         unsigned int data_blocks = desc->data_blocks;
0151 
0152         if (pcm) {
0153             read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
0154             pcm_frames += data_blocks;
0155         }
0156     }
0157 
0158     return pcm_frames;
0159 }
0160 
0161 int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit,
0162           enum amdtp_stream_direction dir)
0163 {
0164     amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
0165 
0166     if (dir == AMDTP_IN_STREAM)
0167         process_ctx_payloads = process_ir_ctx_payloads;
0168     else
0169         process_ctx_payloads = process_it_ctx_payloads;
0170 
0171     return amdtp_stream_init(s, unit, dir, CIP_BLOCKING | CIP_UNAWARE_SYT | CIP_NO_HEADER, 0,
0172                  process_ctx_payloads, sizeof(struct amdtp_ff));
0173 }