Root/
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)); |
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, |
115 | UAC2_CS_CONTROL_CLOCK_VALID - 1)) |
116 | return 1; |
117 | |
118 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, |
119 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
120 | UAC2_CS_CONTROL_CLOCK_VALID << 8, |
121 | snd_usb_ctrl_intf(chip) | (source_id << 8), |
122 | &data, sizeof(data)); |
123 | |
124 | if (err < 0) { |
125 | snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", |
126 | __func__, source_id); |
127 | return 0; |
128 | } |
129 | |
130 | return !!data; |
131 | } |
132 | |
133 | static int __uac_clock_find_source(struct snd_usb_audio *chip, |
134 | int entity_id, unsigned long *visited) |
135 | { |
136 | struct uac_clock_source_descriptor *source; |
137 | struct uac_clock_selector_descriptor *selector; |
138 | struct uac_clock_multiplier_descriptor *multiplier; |
139 | |
140 | entity_id &= 0xff; |
141 | |
142 | if (test_and_set_bit(entity_id, visited)) { |
143 | snd_printk(KERN_WARNING |
144 | "%s(): recursive clock topology detected, id %d.\n", |
145 | __func__, entity_id); |
146 | return -EINVAL; |
147 | } |
148 | |
149 | /* first, see if the ID we're looking for is a clock source already */ |
150 | source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); |
151 | if (source) |
152 | return source->bClockID; |
153 | |
154 | selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); |
155 | if (selector) { |
156 | int ret; |
157 | |
158 | /* the entity ID we are looking for is a selector. |
159 | * find out what it currently selects */ |
160 | ret = uac_clock_selector_get_val(chip, selector->bClockID); |
161 | if (ret < 0) |
162 | return ret; |
163 | |
164 | /* Selector values are one-based */ |
165 | |
166 | if (ret > selector->bNrInPins || ret < 1) { |
167 | printk(KERN_ERR |
168 | "%s(): selector reported illegal value, id %d, ret %d\n", |
169 | __func__, selector->bClockID, ret); |
170 | |
171 | return -EINVAL; |
172 | } |
173 | |
174 | return __uac_clock_find_source(chip, selector->baCSourceID[ret-1], |
175 | visited); |
176 | } |
177 | |
178 | /* FIXME: multipliers only act as pass-thru element for now */ |
179 | multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); |
180 | if (multiplier) |
181 | return __uac_clock_find_source(chip, multiplier->bCSourceID, |
182 | visited); |
183 | |
184 | return -EINVAL; |
185 | } |
186 | |
187 | /* |
188 | * For all kinds of sample rate settings and other device queries, |
189 | * the clock source (end-leaf) must be used. However, clock selectors, |
190 | * clock multipliers and sample rate converters may be specified as |
191 | * clock source input to terminal. This functions walks the clock path |
192 | * to its end and tries to find the source. |
193 | * |
194 | * The 'visited' bitfield is used internally to detect recursive loops. |
195 | * |
196 | * Returns the clock source UnitID (>=0) on success, or an error. |
197 | */ |
198 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id) |
199 | { |
200 | DECLARE_BITMAP(visited, 256); |
201 | memset(visited, 0, sizeof(visited)); |
202 | return __uac_clock_find_source(chip, entity_id, visited); |
203 | } |
204 | |
205 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, |
206 | struct usb_host_interface *alts, |
207 | struct audioformat *fmt, int rate) |
208 | { |
209 | struct usb_device *dev = chip->dev; |
210 | unsigned int ep; |
211 | unsigned char data[3]; |
212 | int err, crate; |
213 | |
214 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
215 | |
216 | /* if endpoint doesn't have sampling rate control, bail out */ |
217 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) |
218 | return 0; |
219 | |
220 | data[0] = rate; |
221 | data[1] = rate >> 8; |
222 | data[2] = rate >> 16; |
223 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
224 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, |
225 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, |
226 | data, sizeof(data))) < 0) { |
227 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", |
228 | dev->devnum, iface, fmt->altsetting, rate, ep); |
229 | return err; |
230 | } |
231 | |
232 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, |
233 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, |
234 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, |
235 | data, sizeof(data))) < 0) { |
236 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", |
237 | dev->devnum, iface, fmt->altsetting, ep); |
238 | return 0; /* some devices don't support reading */ |
239 | } |
240 | |
241 | crate = data[0] | (data[1] << 8) | (data[2] << 16); |
242 | if (crate != rate) { |
243 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); |
244 | // runtime->rate = crate; |
245 | } |
246 | |
247 | return 0; |
248 | } |
249 | |
250 | static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, |
251 | struct usb_host_interface *alts, |
252 | struct audioformat *fmt, int rate) |
253 | { |
254 | struct usb_device *dev = chip->dev; |
255 | unsigned char data[4]; |
256 | int err, cur_rate, prev_rate; |
257 | int clock = snd_usb_clock_find_source(chip, fmt->clock); |
258 | |
259 | if (clock < 0) |
260 | return clock; |
261 | |
262 | if (!uac_clock_source_is_valid(chip, clock)) { |
263 | /* TODO: should we try to find valid clock setups by ourself? */ |
264 | snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n", |
265 | dev->devnum, iface, fmt->altsetting, clock); |
266 | return -ENXIO; |
267 | } |
268 | |
269 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, |
270 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
271 | UAC2_CS_CONTROL_SAM_FREQ << 8, |
272 | snd_usb_ctrl_intf(chip) | (clock << 8), |
273 | data, sizeof(data)); |
274 | if (err < 0) { |
275 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", |
276 | dev->devnum, iface, fmt->altsetting); |
277 | prev_rate = 0; |
278 | } else { |
279 | prev_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); |
280 | } |
281 | |
282 | data[0] = rate; |
283 | data[1] = rate >> 8; |
284 | data[2] = rate >> 16; |
285 | data[3] = rate >> 24; |
286 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, |
287 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, |
288 | UAC2_CS_CONTROL_SAM_FREQ << 8, |
289 | snd_usb_ctrl_intf(chip) | (clock << 8), |
290 | data, sizeof(data))) < 0) { |
291 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", |
292 | dev->devnum, iface, fmt->altsetting, rate); |
293 | return err; |
294 | } |
295 | |
296 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, |
297 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
298 | UAC2_CS_CONTROL_SAM_FREQ << 8, |
299 | snd_usb_ctrl_intf(chip) | (clock << 8), |
300 | data, sizeof(data)); |
301 | if (err < 0) { |
302 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", |
303 | dev->devnum, iface, fmt->altsetting); |
304 | cur_rate = 0; |
305 | } else { |
306 | cur_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); |
307 | } |
308 | |
309 | if (cur_rate != rate) { |
310 | snd_printd(KERN_WARNING |
311 | "current rate %d is different from the runtime rate %d\n", |
312 | cur_rate, rate); |
313 | } |
314 | |
315 | /* Some devices doesn't respond to sample rate changes while the |
316 | * interface is active. */ |
317 | if (rate != prev_rate) { |
318 | usb_set_interface(dev, iface, 0); |
319 | usb_set_interface(dev, iface, fmt->altsetting); |
320 | } |
321 | |
322 | return 0; |
323 | } |
324 | |
325 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, |
326 | struct usb_host_interface *alts, |
327 | struct audioformat *fmt, int rate) |
328 | { |
329 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); |
330 | |
331 | switch (altsd->bInterfaceProtocol) { |
332 | case UAC_VERSION_1: |
333 | default: |
334 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); |
335 | |
336 | case UAC_VERSION_2: |
337 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); |
338 | } |
339 | } |
340 | |
341 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9