Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/pci/echoaudio/gina20_dsp.c
10817 views
1
/****************************************************************************
2
3
Copyright Echo Digital Audio Corporation (c) 1998 - 2004
4
All rights reserved
5
www.echoaudio.com
6
7
This file is part of Echo Digital Audio's generic driver library.
8
9
Echo Digital Audio's generic driver library is free software;
10
you can redistribute it and/or modify it under the terms of
11
the GNU General Public License as published by the Free Software
12
Foundation.
13
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
GNU General Public License for more details.
18
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22
MA 02111-1307, USA.
23
24
*************************************************************************
25
26
Translation from C++ and adaptation for use in ALSA-Driver
27
were made by Giuliano Pochini <[email protected]>
28
29
****************************************************************************/
30
31
32
static int set_professional_spdif(struct echoaudio *chip, char prof);
33
static int update_flags(struct echoaudio *chip);
34
35
36
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
37
{
38
int err;
39
40
DE_INIT(("init_hw() - Gina20\n"));
41
if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20))
42
return -ENODEV;
43
44
if ((err = init_dsp_comm_page(chip))) {
45
DE_INIT(("init_hw - could not initialize DSP comm page\n"));
46
return err;
47
}
48
49
chip->device_id = device_id;
50
chip->subdevice_id = subdevice_id;
51
chip->bad_board = TRUE;
52
chip->dsp_code_to_load = FW_GINA20_DSP;
53
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
54
chip->clock_state = GD_CLOCK_UNDEF;
55
/* Since this card has no ASIC, mark it as loaded so everything
56
works OK */
57
chip->asic_loaded = TRUE;
58
chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
59
ECHO_CLOCK_BIT_SPDIF;
60
61
if ((err = load_firmware(chip)) < 0)
62
return err;
63
chip->bad_board = FALSE;
64
65
DE_INIT(("init_hw done\n"));
66
return err;
67
}
68
69
70
71
static int set_mixer_defaults(struct echoaudio *chip)
72
{
73
chip->professional_spdif = FALSE;
74
return init_line_levels(chip);
75
}
76
77
78
79
static u32 detect_input_clocks(const struct echoaudio *chip)
80
{
81
u32 clocks_from_dsp, clock_bits;
82
83
/* Map the DSP clock detect bits to the generic driver clock
84
detect bits */
85
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
86
87
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
88
89
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
90
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
91
92
return clock_bits;
93
}
94
95
96
97
/* The Gina20 has no ASIC. Just do nothing */
98
static int load_asic(struct echoaudio *chip)
99
{
100
return 0;
101
}
102
103
104
105
static int set_sample_rate(struct echoaudio *chip, u32 rate)
106
{
107
u8 clock_state, spdif_status;
108
109
if (wait_handshake(chip))
110
return -EIO;
111
112
switch (rate) {
113
case 44100:
114
clock_state = GD_CLOCK_44;
115
spdif_status = GD_SPDIF_STATUS_44;
116
break;
117
case 48000:
118
clock_state = GD_CLOCK_48;
119
spdif_status = GD_SPDIF_STATUS_48;
120
break;
121
default:
122
clock_state = GD_CLOCK_NOCHANGE;
123
spdif_status = GD_SPDIF_STATUS_NOCHANGE;
124
break;
125
}
126
127
if (chip->clock_state == clock_state)
128
clock_state = GD_CLOCK_NOCHANGE;
129
if (spdif_status == chip->spdif_status)
130
spdif_status = GD_SPDIF_STATUS_NOCHANGE;
131
132
chip->comm_page->sample_rate = cpu_to_le32(rate);
133
chip->comm_page->gd_clock_state = clock_state;
134
chip->comm_page->gd_spdif_status = spdif_status;
135
chip->comm_page->gd_resampler_state = 3; /* magic number - should always be 3 */
136
137
/* Save the new audio state if it changed */
138
if (clock_state != GD_CLOCK_NOCHANGE)
139
chip->clock_state = clock_state;
140
if (spdif_status != GD_SPDIF_STATUS_NOCHANGE)
141
chip->spdif_status = spdif_status;
142
chip->sample_rate = rate;
143
144
clear_handshake(chip);
145
return send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
146
}
147
148
149
150
static int set_input_clock(struct echoaudio *chip, u16 clock)
151
{
152
DE_ACT(("set_input_clock:\n"));
153
154
switch (clock) {
155
case ECHO_CLOCK_INTERNAL:
156
/* Reset the audio state to unknown (just in case) */
157
chip->clock_state = GD_CLOCK_UNDEF;
158
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
159
set_sample_rate(chip, chip->sample_rate);
160
chip->input_clock = clock;
161
DE_ACT(("Set Gina clock to INTERNAL\n"));
162
break;
163
case ECHO_CLOCK_SPDIF:
164
chip->comm_page->gd_clock_state = GD_CLOCK_SPDIFIN;
165
chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_NOCHANGE;
166
clear_handshake(chip);
167
send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
168
chip->clock_state = GD_CLOCK_SPDIFIN;
169
DE_ACT(("Set Gina20 clock to SPDIF\n"));
170
chip->input_clock = clock;
171
break;
172
default:
173
return -EINVAL;
174
}
175
176
return 0;
177
}
178
179
180
181
/* Set input bus gain (one unit is 0.5dB !) */
182
static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
183
{
184
if (snd_BUG_ON(input >= num_busses_in(chip)))
185
return -EINVAL;
186
187
if (wait_handshake(chip))
188
return -EIO;
189
190
chip->input_gain[input] = gain;
191
gain += GL20_INPUT_GAIN_MAGIC_NUMBER;
192
chip->comm_page->line_in_level[input] = gain;
193
return 0;
194
}
195
196
197
198
/* Tell the DSP to reread the flags from the comm page */
199
static int update_flags(struct echoaudio *chip)
200
{
201
if (wait_handshake(chip))
202
return -EIO;
203
clear_handshake(chip);
204
return send_vector(chip, DSP_VC_UPDATE_FLAGS);
205
}
206
207
208
209
static int set_professional_spdif(struct echoaudio *chip, char prof)
210
{
211
DE_ACT(("set_professional_spdif %d\n", prof));
212
if (prof)
213
chip->comm_page->flags |=
214
cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
215
else
216
chip->comm_page->flags &=
217
~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
218
chip->professional_spdif = prof;
219
return update_flags(chip);
220
}
221
222