diff options
author | Eldad Zack <eldad@fogrefinery.com> | 2013-04-03 17:18:55 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-04-04 02:31:14 -0400 |
commit | 8c55af3f69be6021631628b968cad301d3f294c8 (patch) | |
tree | 049cd4e6cc4aa6c5fb7143d719fecee2f6c93025 /sound/usb/clock.c | |
parent | 06ffc1ebddbed88662a47646ff6aa6a2b41f0aec (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.c | 69 |
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 | ||
102 | static 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 | |||
102 | static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) | 137 | static 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 | ||