aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/pcm.c
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2010-05-31 08:51:31 -0400
committerTakashi Iwai <tiwai@suse.de>2010-05-31 12:16:59 -0400
commit79f920fbff566ffc9de44111eb1456a3cef310f0 (patch)
tree97b574ee648320163fcbcf8793b23e826fb3a1f8 /sound/usb/pcm.c
parent7176d37a28fa4ea7e32815007673f578cdcebf51 (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.c98
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
184static 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
229static 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
264int 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 */