~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/usb/clock.c

Version: ~ [ linux-5.11-rc3 ] ~ [ linux-5.10.7 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.89 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.167 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.215 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.251 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.251 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #include <linux/usb/audio-v3.h>
 27 
 28 #include <sound/core.h>
 29 #include <sound/info.h>
 30 #include <sound/pcm.h>
 31 
 32 #include "usbaudio.h"
 33 #include "card.h"
 34 #include "helper.h"
 35 #include "clock.h"
 36 #include "quirks.h"
 37 
 38 static void *find_uac_clock_desc(struct usb_host_interface *iface, int id,
 39                                  bool (*validator)(void *, int), u8 type)
 40 {
 41         void *cs = NULL;
 42 
 43         while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen,
 44                                              cs, type))) {
 45                 if (validator(cs, id))
 46                         return cs;
 47         }
 48 
 49         return NULL;
 50 }
 51 
 52 static bool validate_clock_source_v2(void *p, int id)
 53 {
 54         struct uac_clock_source_descriptor *cs = p;
 55         return cs->bLength == sizeof(*cs) && cs->bClockID == id;
 56 }
 57 
 58 static bool validate_clock_source_v3(void *p, int id)
 59 {
 60         struct uac3_clock_source_descriptor *cs = p;
 61         return cs->bLength == sizeof(*cs) && cs->bClockID == id;
 62 }
 63 
 64 static bool validate_clock_selector_v2(void *p, int id)
 65 {
 66         struct uac_clock_selector_descriptor *cs = p;
 67         return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
 68                 cs->bLength == 7 + cs->bNrInPins;
 69 }
 70 
 71 static bool validate_clock_selector_v3(void *p, int id)
 72 {
 73         struct uac3_clock_selector_descriptor *cs = p;
 74         return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
 75                 cs->bLength == 11 + cs->bNrInPins;
 76 }
 77 
 78 static bool validate_clock_multiplier_v2(void *p, int id)
 79 {
 80         struct uac_clock_multiplier_descriptor *cs = p;
 81         return cs->bLength == sizeof(*cs) && cs->bClockID == id;
 82 }
 83 
 84 static bool validate_clock_multiplier_v3(void *p, int id)
 85 {
 86         struct uac3_clock_multiplier_descriptor *cs = p;
 87         return cs->bLength == sizeof(*cs) && cs->bClockID == id;
 88 }
 89 
 90 #define DEFINE_FIND_HELPER(name, obj, validator, type)          \
 91 static obj *name(struct usb_host_interface *iface, int id)      \
 92 {                                                               \
 93         return find_uac_clock_desc(iface, id, validator, type); \
 94 }
 95 
 96 DEFINE_FIND_HELPER(snd_usb_find_clock_source,
 97                    struct uac_clock_source_descriptor,
 98                    validate_clock_source_v2, UAC2_CLOCK_SOURCE);
 99 DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3,
100                    struct uac3_clock_source_descriptor,
101                    validate_clock_source_v3, UAC3_CLOCK_SOURCE);
102 
103 DEFINE_FIND_HELPER(snd_usb_find_clock_selector,
104                    struct uac_clock_selector_descriptor,
105                    validate_clock_selector_v2, UAC2_CLOCK_SELECTOR);
106 DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3,
107                    struct uac3_clock_selector_descriptor,
108                    validate_clock_selector_v3, UAC3_CLOCK_SELECTOR);
109 
110 DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
111                    struct uac_clock_multiplier_descriptor,
112                    validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER);
113 DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3,
114                    struct uac3_clock_multiplier_descriptor,
115                    validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER);
116 
117 static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
118 {
119         unsigned char buf;
120         int ret;
121 
122         ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
123                               UAC2_CS_CUR,
124                               USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
125                               UAC2_CX_CLOCK_SELECTOR << 8,
126                               snd_usb_ctrl_intf(chip) | (selector_id << 8),
127                               &buf, sizeof(buf));
128 
129         if (ret < 0)
130                 return ret;
131 
132         return buf;
133 }
134 
135 static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
136                                         unsigned char pin)
137 {
138         int ret;
139 
140         ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
141                               UAC2_CS_CUR,
142                               USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
143                               UAC2_CX_CLOCK_SELECTOR << 8,
144                               snd_usb_ctrl_intf(chip) | (selector_id << 8),
145                               &pin, sizeof(pin));
146         if (ret < 0)
147                 return ret;
148 
149         if (ret != sizeof(pin)) {
150                 usb_audio_err(chip,
151                         "setting selector (id %d) unexpected length %d\n",
152                         selector_id, ret);
153                 return -EINVAL;
154         }
155 
156         ret = uac_clock_selector_get_val(chip, selector_id);
157         if (ret < 0)
158                 return ret;
159 
160         if (ret != pin) {
161                 usb_audio_err(chip,
162                         "setting selector (id %d) to %x failed (current: %d)\n",
163                         selector_id, pin, ret);
164                 return -EINVAL;
165         }
166 
167         return ret;
168 }
169 
170 static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
171                                       int protocol,
172                                       int source_id)
173 {
174         int err;
175         unsigned char data;
176         struct usb_device *dev = chip->dev;
177         u32 bmControls;
178 
179         if (protocol == UAC_VERSION_3) {
180                 struct uac3_clock_source_descriptor *cs_desc =
181                         snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id);
182 
183                 if (!cs_desc)
184                         return 0;
185                 bmControls = le32_to_cpu(cs_desc->bmControls);
186         } else { /* UAC_VERSION_1/2 */
187                 struct uac_clock_source_descriptor *cs_desc =
188                         snd_usb_find_clock_source(chip->ctrl_intf, source_id);
189 
190                 if (!cs_desc)
191                         return 0;
192                 bmControls = cs_desc->bmControls;
193         }
194 
195         /* If a clock source can't tell us whether it's valid, we assume it is */
196         if (!uac_v2v3_control_is_readable(bmControls,
197                                       UAC2_CS_CONTROL_CLOCK_VALID))
198                 return 1;
199 
200         err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
201                               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
202                               UAC2_CS_CONTROL_CLOCK_VALID << 8,
203                               snd_usb_ctrl_intf(chip) | (source_id << 8),
204                               &data, sizeof(data));
205 
206         if (err < 0) {
207                 dev_warn(&dev->dev,
208                          "%s(): cannot get clock validity for id %d\n",
209                            __func__, source_id);
210                 return 0;
211         }
212 
213         return !!data;
214 }
215 
216 static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id,
217                                    unsigned long *visited, bool validate)
218 {
219         struct uac_clock_source_descriptor *source;
220         struct uac_clock_selector_descriptor *selector;
221         struct uac_clock_multiplier_descriptor *multiplier;
222 
223         entity_id &= 0xff;
224 
225         if (test_and_set_bit(entity_id, visited)) {
226                 usb_audio_warn(chip,
227                          "%s(): recursive clock topology detected, id %d.\n",
228                          __func__, entity_id);
229                 return -EINVAL;
230         }
231 
232         /* first, see if the ID we're looking for is a clock source already */
233         source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
234         if (source) {
235                 entity_id = source->bClockID;
236                 if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2,
237                                                                 entity_id)) {
238                         usb_audio_err(chip,
239                                 "clock source %d is not valid, cannot use\n",
240                                 entity_id);
241                         return -ENXIO;
242                 }
243                 return entity_id;
244         }
245 
246         selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
247         if (selector) {
248                 int ret, i, cur;
249 
250                 /* the entity ID we are looking for is a selector.
251                  * find out what it currently selects */
252                 ret = uac_clock_selector_get_val(chip, selector->bClockID);
253                 if (ret < 0)
254                         return ret;
255 
256                 /* Selector values are one-based */
257 
258                 if (ret > selector->bNrInPins || ret < 1) {
259                         usb_audio_err(chip,
260                                 "%s(): selector reported illegal value, id %d, ret %d\n",
261                                 __func__, selector->bClockID, ret);
262 
263                         return -EINVAL;
264                 }
265 
266                 cur = ret;
267                 ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1],
268                                                visited, validate);
269                 if (!validate || ret > 0 || !chip->autoclock)
270                         return ret;
271 
272                 /* The current clock source is invalid, try others. */
273                 for (i = 1; i <= selector->bNrInPins; i++) {
274                         int err;
275 
276                         if (i == cur)
277                                 continue;
278 
279                         ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1],
280                                 visited, true);
281                         if (ret < 0)
282                                 continue;
283 
284                         err = uac_clock_selector_set_val(chip, entity_id, i);
285                         if (err < 0)
286                                 continue;
287 
288                         usb_audio_info(chip,
289                                  "found and selected valid clock source %d\n",
290                                  ret);
291                         return ret;
292                 }
293 
294                 return -ENXIO;
295         }
296 
297         /* FIXME: multipliers only act as pass-thru element for now */
298         multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
299         if (multiplier)
300                 return __uac_clock_find_source(chip, multiplier->bCSourceID,
301                                                 visited, validate);
302 
303         return -EINVAL;
304 }
305 
306 static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
307                                    unsigned long *visited, bool validate)
308 {
309         struct uac3_clock_source_descriptor *source;
310         struct uac3_clock_selector_descriptor *selector;
311         struct uac3_clock_multiplier_descriptor *multiplier;
312 
313         entity_id &= 0xff;
314 
315         if (test_and_set_bit(entity_id, visited)) {
316                 usb_audio_warn(chip,
317                          "%s(): recursive clock topology detected, id %d.\n",
318                          __func__, entity_id);
319                 return -EINVAL;
320         }
321 
322         /* first, see if the ID we're looking for is a clock source already */
323         source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id);
324         if (source) {
325                 entity_id = source->bClockID;
326                 if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3,
327                                                                 entity_id)) {
328                         usb_audio_err(chip,
329                                 "clock source %d is not valid, cannot use\n",
330                                 entity_id);
331                         return -ENXIO;
332                 }
333                 return entity_id;
334         }
335 
336         selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id);
337         if (selector) {
338                 int ret, i, cur;
339 
340                 /* the entity ID we are looking for is a selector.
341                  * find out what it currently selects */
342                 ret = uac_clock_selector_get_val(chip, selector->bClockID);
343                 if (ret < 0)
344                         return ret;
345 
346                 /* Selector values are one-based */
347 
348                 if (ret > selector->bNrInPins || ret < 1) {
349                         usb_audio_err(chip,
350                                 "%s(): selector reported illegal value, id %d, ret %d\n",
351                                 __func__, selector->bClockID, ret);
352 
353                         return -EINVAL;
354                 }
355 
356                 cur = ret;
357                 ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1],
358                                                visited, validate);
359                 if (!validate || ret > 0 || !chip->autoclock)
360                         return ret;
361 
362                 /* The current clock source is invalid, try others. */
363                 for (i = 1; i <= selector->bNrInPins; i++) {
364                         int err;
365 
366                         if (i == cur)
367                                 continue;
368 
369                         ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1],
370                                 visited, true);
371                         if (ret < 0)
372                                 continue;
373 
374                         err = uac_clock_selector_set_val(chip, entity_id, i);
375                         if (err < 0)
376                                 continue;
377 
378                         usb_audio_info(chip,
379                                  "found and selected valid clock source %d\n",
380                                  ret);
381                         return ret;
382                 }
383 
384                 return -ENXIO;
385         }
386 
387         /* FIXME: multipliers only act as pass-thru element for now */
388         multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf,
389                                                       entity_id);
390         if (multiplier)
391                 return __uac3_clock_find_source(chip, multiplier->bCSourceID,
392                                                 visited, validate);
393 
394         return -EINVAL;
395 }
396 
397 /*
398  * For all kinds of sample rate settings and other device queries,
399  * the clock source (end-leaf) must be used. However, clock selectors,
400  * clock multipliers and sample rate converters may be specified as
401  * clock source input to terminal. This functions walks the clock path
402  * to its end and tries to find the source.
403  *
404  * The 'visited' bitfield is used internally to detect recursive loops.
405  *
406  * Returns the clock source UnitID (>=0) on success, or an error.
407  */
408 int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol,
409                               int entity_id, bool validate)
410 {
411         DECLARE_BITMAP(visited, 256);
412         memset(visited, 0, sizeof(visited));
413 
414         switch (protocol) {
415         case UAC_VERSION_2:
416                 return __uac_clock_find_source(chip, entity_id, visited,
417                                                validate);
418         case UAC_VERSION_3:
419                 return __uac3_clock_find_source(chip, entity_id, visited,
420                                                validate);
421         default:
422                 return -EINVAL;
423         }
424 }
425 
426 static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
427                               struct usb_host_interface *alts,
428                               struct audioformat *fmt, int rate)
429 {
430         struct usb_device *dev = chip->dev;
431         unsigned int ep;
432         unsigned char data[3];
433         int err, crate;
434 
435         if (get_iface_desc(alts)->bNumEndpoints < 1)
436                 return -EINVAL;
437         ep = get_endpoint(alts, 0)->bEndpointAddress;
438 
439         /* if endpoint doesn't have sampling rate control, bail out */
440         if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE))
441                 return 0;
442 
443         data[0] = rate;
444         data[1] = rate >> 8;
445         data[2] = rate >> 16;
446         err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
447                               USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
448                               UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
449                               data, sizeof(data));
450         if (err < 0) {
451                 dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n",
452                         iface, fmt->altsetting, rate, ep);
453                 return err;
454         }
455 
456         /* Don't check the sample rate for devices which we know don't
457          * support reading */
458         if (snd_usb_get_sample_rate_quirk(chip))
459                 return 0;
460         /* the firmware is likely buggy, don't repeat to fail too many times */
461         if (chip->sample_rate_read_error > 2)
462                 return 0;
463 
464         err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
465                               USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
466                               UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
467                               data, sizeof(data));
468         if (err < 0) {
469                 dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n",
470                         iface, fmt->altsetting, ep);
471                 chip->sample_rate_read_error++;
472                 return 0; /* some devices don't support reading */
473         }
474 
475         crate = data[0] | (data[1] << 8) | (data[2] << 16);
476         if (crate != rate) {
477                 dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate);
478                 // runtime->rate = crate;
479         }
480 
481         return 0;
482 }
483 
484 static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
485                               int altsetting, int clock)
486 {
487         struct usb_device *dev = chip->dev;
488         __le32 data;
489         int err;
490 
491         err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
492                               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
493                               UAC2_CS_CONTROL_SAM_FREQ << 8,
494                               snd_usb_ctrl_intf(chip) | (clock << 8),
495                               &data, sizeof(data));
496         if (err < 0) {
497                 dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
498                          iface, altsetting, err);
499                 return 0;
500         }
501 
502         return le32_to_cpu(data);
503 }
504 
505 static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
506                               struct usb_host_interface *alts,
507                               struct audioformat *fmt, int rate)
508 {
509         struct usb_device *dev = chip->dev;
510         __le32 data;
511         int err, cur_rate, prev_rate;
512         int clock;
513         bool writeable;
514         u32 bmControls;
515 
516         clock = snd_usb_clock_find_source(chip, fmt->protocol,
517                                           fmt->clock, true);
518         if (clock < 0)
519                 return clock;
520 
521         prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock);
522         if (prev_rate == rate)
523                 return 0;
524 
525         if (fmt->protocol == UAC_VERSION_3) {
526                 struct uac3_clock_source_descriptor *cs_desc;
527 
528                 cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock);
529                 bmControls = le32_to_cpu(cs_desc->bmControls);
530         } else {
531                 struct uac_clock_source_descriptor *cs_desc;
532 
533                 cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
534                 bmControls = cs_desc->bmControls;
535         }
536 
537         writeable = uac_v2v3_control_is_writeable(bmControls,
538                                                   UAC2_CS_CONTROL_SAM_FREQ);
539         if (writeable) {
540                 data = cpu_to_le32(rate);
541                 err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
542                                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
543                                       UAC2_CS_CONTROL_SAM_FREQ << 8,
544                                       snd_usb_ctrl_intf(chip) | (clock << 8),
545                                       &data, sizeof(data));
546                 if (err < 0) {
547                         usb_audio_err(chip,
548                                 "%d:%d: cannot set freq %d (v2/v3): err %d\n",
549                                 iface, fmt->altsetting, rate, err);
550                         return err;
551                 }
552 
553                 cur_rate = get_sample_rate_v2v3(chip, iface,
554                                                 fmt->altsetting, clock);
555         } else {
556                 cur_rate = prev_rate;
557         }
558 
559         if (cur_rate != rate) {
560                 if (!writeable) {
561                         usb_audio_warn(chip,
562                                  "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
563                                  iface, fmt->altsetting, rate, cur_rate);
564                         return -ENXIO;
565                 }
566                 usb_audio_dbg(chip,
567                         "current rate %d is different from the runtime rate %d\n",
568                         cur_rate, rate);
569         }
570 
571         /* Some devices doesn't respond to sample rate changes while the
572          * interface is active. */
573         if (rate != prev_rate) {
574                 usb_set_interface(dev, iface, 0);
575                 snd_usb_set_interface_quirk(dev);
576                 usb_set_interface(dev, iface, fmt->altsetting);
577                 snd_usb_set_interface_quirk(dev);
578         }
579 
580         return 0;
581 }
582 
583 int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
584                              struct usb_host_interface *alts,
585                              struct audioformat *fmt, int rate)
586 {
587         switch (fmt->protocol) {
588         case UAC_VERSION_1:
589         default:
590                 return set_sample_rate_v1(chip, iface, alts, fmt, rate);
591 
592         case UAC_VERSION_3:
593                 if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
594                         if (rate != UAC3_BADD_SAMPLING_RATE)
595                                 return -ENXIO;
596                         else
597                                 return 0;
598                 }
599         /* fall through */
600         case UAC_VERSION_2:
601                 return set_sample_rate_v2v3(chip, iface, alts, fmt, rate);
602         }
603 }
604 
605 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp