aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/clock.c
diff options
context:
space:
mode:
authorEldad Zack <eldad@fogrefinery.com>2013-04-03 17:18:55 -0400
committerTakashi Iwai <tiwai@suse.de>2013-04-04 02:31:14 -0400
commit8c55af3f69be6021631628b968cad301d3f294c8 (patch)
tree049cd4e6cc4aa6c5fb7143d719fecee2f6c93025 /sound/usb/clock.c
parent06ffc1ebddbed88662a47646ff6aa6a2b41f0aec (diff)
ALSA: usb-audio: UAC2: try to find and switch to valid clock
If a selector is available on a device, it may be pointing to a clock source which is currently invalid. If there is a valid clock source which can be selected, switch to it. Signed-off-by: Eldad Zack <eldad@fogrefinery.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/clock.c')
-rw-r--r--sound/usb/clock.c69
1 files changed, 66 insertions, 3 deletions
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 0c98f52a1c9c..d7ab2d75aefd 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -99,6 +99,41 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
99 return buf; 99 return buf;
100} 100}
101 101
102static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
103 unsigned char pin)
104{
105 int ret;
106
107 ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
108 UAC2_CS_CUR,
109 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
110 UAC2_CX_CLOCK_SELECTOR << 8,
111 snd_usb_ctrl_intf(chip) | (selector_id << 8),
112 &pin, sizeof(pin));
113 if (ret < 0)
114 return ret;
115
116 if (ret != sizeof(pin)) {
117 snd_printk(KERN_ERR
118 "usb-audio:%d: setting selector (id %d) unexpected length %d\n",
119 chip->dev->devnum, selector_id, ret);
120 return -EINVAL;
121 }
122
123 ret = uac_clock_selector_get_val(chip, selector_id);
124 if (ret < 0)
125 return ret;
126
127 if (ret != pin) {
128 snd_printk(KERN_ERR
129 "usb-audio:%d: setting selector (id %d) to %x failed (current: %d)\n",
130 chip->dev->devnum, selector_id, pin, ret);
131 return -EINVAL;
132 }
133
134 return ret;
135}
136
102static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) 137static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
103{ 138{
104 int err; 139 int err;
@@ -161,7 +196,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
161 196
162 selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); 197 selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
163 if (selector) { 198 if (selector) {
164 int ret; 199 int ret, i, cur;
165 200
166 /* the entity ID we are looking for is a selector. 201 /* the entity ID we are looking for is a selector.
167 * find out what it currently selects */ 202 * find out what it currently selects */
@@ -179,8 +214,35 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
179 return -EINVAL; 214 return -EINVAL;
180 } 215 }
181 216
182 return __uac_clock_find_source(chip, selector->baCSourceID[ret-1], 217 cur = ret;
218 ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1],
183 visited, validate); 219 visited, validate);
220 if (!validate || ret > 0)
221 return ret;
222
223 /* The current clock source is invalid, try others. */
224 for (i = 1; i <= selector->bNrInPins; i++) {
225 int err;
226
227 if (i == cur)
228 continue;
229
230 ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1],
231 visited, true);
232 if (ret < 0)
233 continue;
234
235 err = uac_clock_selector_set_val(chip, entity_id, i);
236 if (err < 0)
237 continue;
238
239 snd_printk(KERN_INFO
240 "usb-audio:%d: found and selected valid clock source %d\n",
241 chip->dev->devnum, ret);
242 return ret;
243 }
244
245 return -ENXIO;
184 } 246 }
185 247
186 /* FIXME: multipliers only act as pass-thru element for now */ 248 /* FIXME: multipliers only act as pass-thru element for now */
@@ -284,8 +346,9 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
284 struct usb_device *dev = chip->dev; 346 struct usb_device *dev = chip->dev;
285 __le32 data; 347 __le32 data;
286 int err, cur_rate, prev_rate; 348 int err, cur_rate, prev_rate;
287 int clock = snd_usb_clock_find_source(chip, fmt->clock, true); 349 int clock;
288 350
351 clock = snd_usb_clock_find_source(chip, fmt->clock, true);
289 if (clock < 0) 352 if (clock < 0)
290 return clock; 353 return clock;
291 354