diff options
author | Daniel Mack <daniel@caiaq.de> | 2010-05-31 08:51:31 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-05-31 12:16:59 -0400 |
commit | 79f920fbff566ffc9de44111eb1456a3cef310f0 (patch) | |
tree | 97b574ee648320163fcbcf8793b23e826fb3a1f8 /sound/usb/pcm.c | |
parent | 7176d37a28fa4ea7e32815007673f578cdcebf51 (diff) |
ALSA: usb-audio: parse clock topology of UAC2 devices
Audio devices which comply to the UAC2 standard can export complex clock
topologies in its descriptors and set up links between them.
The entities that are defined are
- clock sources, which define the end-leafs.
- clock selectors, which act as switch to select one out of many
possible clocks sources.
- clock multipliers, which have an input clock source, and act as clock
source again. They can be used to derive one clock from another.
All sample rate changes, clock validity queries and the like must go to
clock source elements, while clock selectors and multipliers can be used
as terminal clock source.
The following patch adds a parser for these elements and functions to
iterate over the tree and find the leaf nodes (clock sources).
The samplerate set functions were moved to the new clock.c file.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r-- | sound/usb/pcm.c | 98 |
1 files changed, 1 insertions, 97 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 056587de7be4..456829882f40 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "urb.h" | 31 | #include "urb.h" |
32 | #include "helper.h" | 32 | #include "helper.h" |
33 | #include "pcm.h" | 33 | #include "pcm.h" |
34 | #include "clock.h" | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * return the current pcm pointer. just based on the hwptr_done value. | 37 | * return the current pcm pointer. just based on the hwptr_done value. |
@@ -181,103 +182,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | |||
181 | return -EINVAL; | 182 | return -EINVAL; |
182 | } | 183 | } |
183 | 184 | ||
184 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | ||
185 | struct usb_host_interface *alts, | ||
186 | struct audioformat *fmt, int rate) | ||
187 | { | ||
188 | struct usb_device *dev = chip->dev; | ||
189 | unsigned int ep; | ||
190 | unsigned char data[3]; | ||
191 | int err, crate; | ||
192 | |||
193 | ep = get_endpoint(alts, 0)->bEndpointAddress; | ||
194 | /* if endpoint doesn't have sampling rate control, bail out */ | ||
195 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { | ||
196 | snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", | ||
197 | dev->devnum, iface, fmt->altsetting); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | data[0] = rate; | ||
202 | data[1] = rate >> 8; | ||
203 | data[2] = rate >> 16; | ||
204 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | ||
205 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | ||
206 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
207 | data, sizeof(data), 1000)) < 0) { | ||
208 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", | ||
209 | dev->devnum, iface, fmt->altsetting, rate, ep); | ||
210 | return err; | ||
211 | } | ||
212 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, | ||
213 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, | ||
214 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
215 | data, sizeof(data), 1000)) < 0) { | ||
216 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", | ||
217 | dev->devnum, iface, fmt->altsetting, ep); | ||
218 | return 0; /* some devices don't support reading */ | ||
219 | } | ||
220 | crate = data[0] | (data[1] << 8) | (data[2] << 16); | ||
221 | if (crate != rate) { | ||
222 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
223 | // runtime->rate = crate; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | ||
230 | struct usb_host_interface *alts, | ||
231 | struct audioformat *fmt, int rate) | ||
232 | { | ||
233 | struct usb_device *dev = chip->dev; | ||
234 | unsigned char data[4]; | ||
235 | int err, crate; | ||
236 | |||
237 | data[0] = rate; | ||
238 | data[1] = rate >> 8; | ||
239 | data[2] = rate >> 16; | ||
240 | data[3] = rate >> 24; | ||
241 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | ||
242 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
243 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | ||
244 | data, sizeof(data), 1000)) < 0) { | ||
245 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", | ||
246 | dev->devnum, iface, fmt->altsetting, rate); | ||
247 | return err; | ||
248 | } | ||
249 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | ||
250 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
251 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | ||
252 | data, sizeof(data), 1000)) < 0) { | ||
253 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", | ||
254 | dev->devnum, iface, fmt->altsetting); | ||
255 | return err; | ||
256 | } | ||
257 | crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | ||
258 | if (crate != rate) | ||
259 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | ||
265 | struct usb_host_interface *alts, | ||
266 | struct audioformat *fmt, int rate) | ||
267 | { | ||
268 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | ||
269 | |||
270 | switch (altsd->bInterfaceProtocol) { | ||
271 | case UAC_VERSION_1: | ||
272 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | ||
273 | |||
274 | case UAC_VERSION_2: | ||
275 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); | ||
276 | } | ||
277 | |||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | /* | 185 | /* |
282 | * find a matching format and set up the interface | 186 | * find a matching format and set up the interface |
283 | */ | 187 | */ |