Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/fireface/amdtp-ff.c
26451 views
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
11
struct amdtp_ff {
12
unsigned int pcm_channels;
13
};
14
15
int 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, 1);
28
}
29
30
static 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
60
static 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
90
static 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
103
int 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
115
static void process_it_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc,
116
unsigned int count, struct snd_pcm_substream *pcm)
117
{
118
unsigned int pcm_frames = 0;
119
int i;
120
121
for (i = 0; i < count; ++i) {
122
__le32 *buf = (__le32 *)desc->ctx_payload;
123
unsigned int data_blocks = desc->data_blocks;
124
125
if (pcm) {
126
write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
127
pcm_frames += data_blocks;
128
} else {
129
write_pcm_silence(s, buf, data_blocks);
130
}
131
132
desc = amdtp_stream_next_packet_desc(s, desc);
133
}
134
}
135
136
static void process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc,
137
unsigned int count, struct snd_pcm_substream *pcm)
138
{
139
unsigned int pcm_frames = 0;
140
int i;
141
142
for (i = 0; i < count; ++i) {
143
__le32 *buf = (__le32 *)desc->ctx_payload;
144
unsigned int data_blocks = desc->data_blocks;
145
146
if (pcm) {
147
read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
148
pcm_frames += data_blocks;
149
}
150
151
desc = amdtp_stream_next_packet_desc(s, desc);
152
}
153
}
154
155
int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit,
156
enum amdtp_stream_direction dir)
157
{
158
amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
159
160
if (dir == AMDTP_IN_STREAM)
161
process_ctx_payloads = process_ir_ctx_payloads;
162
else
163
process_ctx_payloads = process_it_ctx_payloads;
164
165
return amdtp_stream_init(s, unit, dir, CIP_BLOCKING | CIP_UNAWARE_SYT | CIP_NO_HEADER, 0,
166
process_ctx_payloads, sizeof(struct amdtp_ff));
167
}
168
169