Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/usb/clock.c
10814 views
1
/*
2
* Clock domain and sample rate management functions
3
*
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
8
*
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
*
18
*/
19
20
#include <linux/bitops.h>
21
#include <linux/init.h>
22
#include <linux/string.h>
23
#include <linux/usb.h>
24
#include <linux/usb/audio.h>
25
#include <linux/usb/audio-v2.h>
26
27
#include <sound/core.h>
28
#include <sound/info.h>
29
#include <sound/pcm.h>
30
31
#include "usbaudio.h"
32
#include "card.h"
33
#include "helper.h"
34
#include "clock.h"
35
36
static struct uac_clock_source_descriptor *
37
snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
38
int clock_id)
39
{
40
struct uac_clock_source_descriptor *cs = NULL;
41
42
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
43
ctrl_iface->extralen,
44
cs, UAC2_CLOCK_SOURCE))) {
45
if (cs->bClockID == clock_id)
46
return cs;
47
}
48
49
return NULL;
50
}
51
52
static struct uac_clock_selector_descriptor *
53
snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface,
54
int clock_id)
55
{
56
struct uac_clock_selector_descriptor *cs = NULL;
57
58
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
59
ctrl_iface->extralen,
60
cs, UAC2_CLOCK_SELECTOR))) {
61
if (cs->bClockID == clock_id)
62
return cs;
63
}
64
65
return NULL;
66
}
67
68
static struct uac_clock_multiplier_descriptor *
69
snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface,
70
int clock_id)
71
{
72
struct uac_clock_multiplier_descriptor *cs = NULL;
73
74
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
75
ctrl_iface->extralen,
76
cs, UAC2_CLOCK_MULTIPLIER))) {
77
if (cs->bClockID == clock_id)
78
return cs;
79
}
80
81
return NULL;
82
}
83
84
static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
85
{
86
unsigned char buf;
87
int ret;
88
89
ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
90
UAC2_CS_CUR,
91
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
92
UAC2_CX_CLOCK_SELECTOR << 8,
93
snd_usb_ctrl_intf(chip) | (selector_id << 8),
94
&buf, sizeof(buf), 1000);
95
96
if (ret < 0)
97
return ret;
98
99
return buf;
100
}
101
102
static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
103
{
104
int err;
105
unsigned char data;
106
struct usb_device *dev = chip->dev;
107
struct uac_clock_source_descriptor *cs_desc =
108
snd_usb_find_clock_source(chip->ctrl_intf, source_id);
109
110
if (!cs_desc)
111
return 0;
112
113
/* If a clock source can't tell us whether it's valid, we assume it is */
114
if (!uac2_control_is_readable(cs_desc->bmControls, UAC2_CS_CONTROL_CLOCK_VALID))
115
return 1;
116
117
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
118
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
119
UAC2_CS_CONTROL_CLOCK_VALID << 8,
120
snd_usb_ctrl_intf(chip) | (source_id << 8),
121
&data, sizeof(data), 1000);
122
123
if (err < 0) {
124
snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
125
__func__, source_id);
126
return 0;
127
}
128
129
return !!data;
130
}
131
132
static int __uac_clock_find_source(struct snd_usb_audio *chip,
133
int entity_id, unsigned long *visited)
134
{
135
struct uac_clock_source_descriptor *source;
136
struct uac_clock_selector_descriptor *selector;
137
struct uac_clock_multiplier_descriptor *multiplier;
138
139
entity_id &= 0xff;
140
141
if (test_and_set_bit(entity_id, visited)) {
142
snd_printk(KERN_WARNING
143
"%s(): recursive clock topology detected, id %d.\n",
144
__func__, entity_id);
145
return -EINVAL;
146
}
147
148
/* first, see if the ID we're looking for is a clock source already */
149
source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
150
if (source)
151
return source->bClockID;
152
153
selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
154
if (selector) {
155
int ret;
156
157
/* the entity ID we are looking for is a selector.
158
* find out what it currently selects */
159
ret = uac_clock_selector_get_val(chip, selector->bClockID);
160
if (ret < 0)
161
return ret;
162
163
/* Selector values are one-based */
164
165
if (ret > selector->bNrInPins || ret < 1) {
166
printk(KERN_ERR
167
"%s(): selector reported illegal value, id %d, ret %d\n",
168
__func__, selector->bClockID, ret);
169
170
return -EINVAL;
171
}
172
173
return __uac_clock_find_source(chip, selector->baCSourceID[ret-1],
174
visited);
175
}
176
177
/* FIXME: multipliers only act as pass-thru element for now */
178
multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
179
if (multiplier)
180
return __uac_clock_find_source(chip, multiplier->bCSourceID,
181
visited);
182
183
return -EINVAL;
184
}
185
186
/*
187
* For all kinds of sample rate settings and other device queries,
188
* the clock source (end-leaf) must be used. However, clock selectors,
189
* clock multipliers and sample rate converters may be specified as
190
* clock source input to terminal. This functions walks the clock path
191
* to its end and tries to find the source.
192
*
193
* The 'visited' bitfield is used internally to detect recursive loops.
194
*
195
* Returns the clock source UnitID (>=0) on success, or an error.
196
*/
197
int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id)
198
{
199
DECLARE_BITMAP(visited, 256);
200
memset(visited, 0, sizeof(visited));
201
return __uac_clock_find_source(chip, entity_id, visited);
202
}
203
204
static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
205
struct usb_host_interface *alts,
206
struct audioformat *fmt, int rate)
207
{
208
struct usb_device *dev = chip->dev;
209
unsigned int ep;
210
unsigned char data[3];
211
int err, crate;
212
213
ep = get_endpoint(alts, 0)->bEndpointAddress;
214
215
/* if endpoint doesn't have sampling rate control, bail out */
216
if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE))
217
return 0;
218
219
data[0] = rate;
220
data[1] = rate >> 8;
221
data[2] = rate >> 16;
222
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
223
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
224
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
225
data, sizeof(data), 1000)) < 0) {
226
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
227
dev->devnum, iface, fmt->altsetting, rate, ep);
228
return err;
229
}
230
231
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
232
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
233
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
234
data, sizeof(data), 1000)) < 0) {
235
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
236
dev->devnum, iface, fmt->altsetting, ep);
237
return 0; /* some devices don't support reading */
238
}
239
240
crate = data[0] | (data[1] << 8) | (data[2] << 16);
241
if (crate != rate) {
242
snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
243
// runtime->rate = crate;
244
}
245
246
return 0;
247
}
248
249
static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
250
struct usb_host_interface *alts,
251
struct audioformat *fmt, int rate)
252
{
253
struct usb_device *dev = chip->dev;
254
unsigned char data[4];
255
int err, crate;
256
int clock = snd_usb_clock_find_source(chip, fmt->clock);
257
258
if (clock < 0)
259
return clock;
260
261
if (!uac_clock_source_is_valid(chip, clock)) {
262
/* TODO: should we try to find valid clock setups by ourself? */
263
snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n",
264
dev->devnum, iface, fmt->altsetting, clock);
265
return -ENXIO;
266
}
267
268
data[0] = rate;
269
data[1] = rate >> 8;
270
data[2] = rate >> 16;
271
data[3] = rate >> 24;
272
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
273
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
274
UAC2_CS_CONTROL_SAM_FREQ << 8,
275
snd_usb_ctrl_intf(chip) | (clock << 8),
276
data, sizeof(data), 1000)) < 0) {
277
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
278
dev->devnum, iface, fmt->altsetting, rate);
279
return err;
280
}
281
282
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
283
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
284
UAC2_CS_CONTROL_SAM_FREQ << 8,
285
snd_usb_ctrl_intf(chip) | (clock << 8),
286
data, sizeof(data), 1000)) < 0) {
287
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
288
dev->devnum, iface, fmt->altsetting);
289
return err;
290
}
291
292
crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
293
if (crate != rate)
294
snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
295
296
return 0;
297
}
298
299
int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
300
struct usb_host_interface *alts,
301
struct audioformat *fmt, int rate)
302
{
303
struct usb_interface_descriptor *altsd = get_iface_desc(alts);
304
305
switch (altsd->bInterfaceProtocol) {
306
case UAC_VERSION_1:
307
default:
308
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
309
310
case UAC_VERSION_2:
311
return set_sample_rate_v2(chip, iface, alts, fmt, rate);
312
}
313
}
314
315
316