implicit.c (14774B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2// 3// Special handling for implicit feedback mode 4// 5 6#include <linux/init.h> 7#include <linux/usb.h> 8#include <linux/usb/audio.h> 9#include <linux/usb/audio-v2.h> 10 11#include <sound/core.h> 12#include <sound/pcm.h> 13#include <sound/pcm_params.h> 14 15#include "usbaudio.h" 16#include "card.h" 17#include "helper.h" 18#include "implicit.h" 19 20enum { 21 IMPLICIT_FB_NONE, 22 IMPLICIT_FB_GENERIC, 23 IMPLICIT_FB_FIXED, 24 IMPLICIT_FB_BOTH, /* generic playback + capture (for BOSS) */ 25}; 26 27struct snd_usb_implicit_fb_match { 28 unsigned int id; 29 unsigned int iface_class; 30 unsigned int ep_num; 31 unsigned int iface; 32 int type; 33}; 34 35#define IMPLICIT_FB_GENERIC_DEV(vend, prod) \ 36 { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_GENERIC } 37#define IMPLICIT_FB_FIXED_DEV(vend, prod, ep, ifnum) \ 38 { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_FIXED, .ep_num = (ep),\ 39 .iface = (ifnum) } 40#define IMPLICIT_FB_BOTH_DEV(vend, prod, ep, ifnum) \ 41 { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_BOTH, .ep_num = (ep),\ 42 .iface = (ifnum) } 43#define IMPLICIT_FB_SKIP_DEV(vend, prod) \ 44 { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_NONE } 45 46/* Implicit feedback quirk table for playback */ 47static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { 48 /* Fixed EP */ 49 /* FIXME: check the availability of generic matching */ 50 IMPLICIT_FB_FIXED_DEV(0x0763, 0x2080, 0x81, 2), /* M-Audio FastTrack Ultra */ 51 IMPLICIT_FB_FIXED_DEV(0x0763, 0x2081, 0x81, 2), /* M-Audio FastTrack Ultra */ 52 IMPLICIT_FB_FIXED_DEV(0x2466, 0x8010, 0x81, 2), /* Fractal Audio Axe-Fx III */ 53 IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0001, 0x81, 2), /* Solid State Logic SSL2 */ 54 IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */ 55 IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */ 56 IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */ 57 IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */ 58 IMPLICIT_FB_FIXED_DEV(0x1686, 0xf029, 0x82, 2), /* Zoom UAC-2 */ 59 IMPLICIT_FB_FIXED_DEV(0x2466, 0x8003, 0x86, 2), /* Fractal Audio Axe-Fx II */ 60 IMPLICIT_FB_FIXED_DEV(0x0499, 0x172a, 0x86, 2), /* Yamaha MODX */ 61 62 /* Special matching */ 63 { .id = USB_ID(0x07fd, 0x0004), .iface_class = USB_CLASS_AUDIO, 64 .type = IMPLICIT_FB_NONE }, /* MicroBook IIc */ 65 /* ep = 0x84, ifnum = 0 */ 66 { .id = USB_ID(0x07fd, 0x0004), .iface_class = USB_CLASS_VENDOR_SPEC, 67 .type = IMPLICIT_FB_FIXED, 68 .ep_num = 0x84, .iface = 0 }, /* MOTU MicroBook II */ 69 70 {} /* terminator */ 71}; 72 73/* Implicit feedback quirk table for capture: only FIXED type */ 74static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { 75 {} /* terminator */ 76}; 77 78/* set up sync EP information on the audioformat */ 79static int add_implicit_fb_sync_ep(struct snd_usb_audio *chip, 80 struct audioformat *fmt, 81 int ep, int ep_idx, int ifnum, 82 const struct usb_host_interface *alts) 83{ 84 struct usb_interface *iface; 85 86 if (!alts) { 87 iface = usb_ifnum_to_if(chip->dev, ifnum); 88 if (!iface || iface->num_altsetting < 2) 89 return 0; 90 alts = &iface->altsetting[1]; 91 } 92 93 fmt->sync_ep = ep; 94 fmt->sync_iface = ifnum; 95 fmt->sync_altsetting = alts->desc.bAlternateSetting; 96 fmt->sync_ep_idx = ep_idx; 97 fmt->implicit_fb = 1; 98 usb_audio_dbg(chip, 99 "%d:%d: added %s implicit_fb sync_ep %x, iface %d:%d\n", 100 fmt->iface, fmt->altsetting, 101 (ep & USB_DIR_IN) ? "playback" : "capture", 102 fmt->sync_ep, fmt->sync_iface, fmt->sync_altsetting); 103 return 1; 104} 105 106/* Check whether the given UAC2 iface:altset points to an implicit fb source */ 107static int add_generic_uac2_implicit_fb(struct snd_usb_audio *chip, 108 struct audioformat *fmt, 109 unsigned int ifnum, 110 unsigned int altsetting) 111{ 112 struct usb_host_interface *alts; 113 struct usb_endpoint_descriptor *epd; 114 115 alts = snd_usb_get_host_interface(chip, ifnum, altsetting); 116 if (!alts) 117 return 0; 118 if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || 119 alts->desc.bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING || 120 alts->desc.bInterfaceProtocol != UAC_VERSION_2 || 121 alts->desc.bNumEndpoints < 1) 122 return 0; 123 epd = get_endpoint(alts, 0); 124 if (!usb_endpoint_is_isoc_in(epd) || 125 (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != 126 USB_ENDPOINT_USAGE_IMPLICIT_FB) 127 return 0; 128 return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0, 129 ifnum, alts); 130} 131 132static bool roland_sanity_check_iface(struct usb_host_interface *alts) 133{ 134 if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC || 135 (alts->desc.bInterfaceSubClass != 2 && 136 alts->desc.bInterfaceProtocol != 2) || 137 alts->desc.bNumEndpoints < 1) 138 return false; 139 return true; 140} 141 142/* Like the UAC2 case above, but specific to Roland with vendor class and hack */ 143static int add_roland_implicit_fb(struct snd_usb_audio *chip, 144 struct audioformat *fmt, 145 struct usb_host_interface *alts) 146{ 147 struct usb_endpoint_descriptor *epd; 148 149 if (!roland_sanity_check_iface(alts)) 150 return 0; 151 /* only when both streams are with ASYNC type */ 152 epd = get_endpoint(alts, 0); 153 if (!usb_endpoint_is_isoc_out(epd) || 154 (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) 155 return 0; 156 157 /* check capture EP */ 158 alts = snd_usb_get_host_interface(chip, 159 alts->desc.bInterfaceNumber + 1, 160 alts->desc.bAlternateSetting); 161 if (!alts || !roland_sanity_check_iface(alts)) 162 return 0; 163 epd = get_endpoint(alts, 0); 164 if (!usb_endpoint_is_isoc_in(epd) || 165 (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) 166 return 0; 167 chip->quirk_flags |= QUIRK_FLAG_PLAYBACK_FIRST; 168 return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0, 169 alts->desc.bInterfaceNumber, alts); 170} 171 172/* capture quirk for Roland device; always full-duplex */ 173static int add_roland_capture_quirk(struct snd_usb_audio *chip, 174 struct audioformat *fmt, 175 struct usb_host_interface *alts) 176{ 177 struct usb_endpoint_descriptor *epd; 178 179 if (!roland_sanity_check_iface(alts)) 180 return 0; 181 epd = get_endpoint(alts, 0); 182 if (!usb_endpoint_is_isoc_in(epd) || 183 (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) 184 return 0; 185 186 alts = snd_usb_get_host_interface(chip, 187 alts->desc.bInterfaceNumber - 1, 188 alts->desc.bAlternateSetting); 189 if (!alts || !roland_sanity_check_iface(alts)) 190 return 0; 191 epd = get_endpoint(alts, 0); 192 if (!usb_endpoint_is_isoc_out(epd)) 193 return 0; 194 return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0, 195 alts->desc.bInterfaceNumber, alts); 196} 197 198/* Playback and capture EPs on Pioneer devices share the same iface/altset 199 * for the implicit feedback operation 200 */ 201static bool is_pioneer_implicit_fb(struct snd_usb_audio *chip, 202 struct usb_host_interface *alts) 203 204{ 205 struct usb_endpoint_descriptor *epd; 206 207 if (USB_ID_VENDOR(chip->usb_id) != 0x2b73 && 208 USB_ID_VENDOR(chip->usb_id) != 0x08e4) 209 return false; 210 if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) 211 return false; 212 if (alts->desc.bNumEndpoints != 2) 213 return false; 214 215 epd = get_endpoint(alts, 0); 216 if (!usb_endpoint_is_isoc_out(epd) || 217 (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) 218 return false; 219 220 epd = get_endpoint(alts, 1); 221 if (!usb_endpoint_is_isoc_in(epd) || 222 (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC || 223 ((epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != 224 USB_ENDPOINT_USAGE_DATA && 225 (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != 226 USB_ENDPOINT_USAGE_IMPLICIT_FB)) 227 return false; 228 229 return true; 230} 231 232static int __add_generic_implicit_fb(struct snd_usb_audio *chip, 233 struct audioformat *fmt, 234 int iface, int altset) 235{ 236 struct usb_host_interface *alts; 237 struct usb_endpoint_descriptor *epd; 238 239 alts = snd_usb_get_host_interface(chip, iface, altset); 240 if (!alts) 241 return 0; 242 243 if ((alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC && 244 alts->desc.bInterfaceClass != USB_CLASS_AUDIO) || 245 alts->desc.bNumEndpoints < 1) 246 return 0; 247 epd = get_endpoint(alts, 0); 248 if (!usb_endpoint_is_isoc_in(epd) || 249 (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) 250 return 0; 251 return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0, 252 iface, alts); 253} 254 255/* More generic quirk: look for the sync EP next to the data EP */ 256static int add_generic_implicit_fb(struct snd_usb_audio *chip, 257 struct audioformat *fmt, 258 struct usb_host_interface *alts) 259{ 260 if ((fmt->ep_attr & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) 261 return 0; 262 263 if (__add_generic_implicit_fb(chip, fmt, 264 alts->desc.bInterfaceNumber + 1, 265 alts->desc.bAlternateSetting)) 266 return 1; 267 return __add_generic_implicit_fb(chip, fmt, 268 alts->desc.bInterfaceNumber - 1, 269 alts->desc.bAlternateSetting); 270} 271 272static const struct snd_usb_implicit_fb_match * 273find_implicit_fb_entry(struct snd_usb_audio *chip, 274 const struct snd_usb_implicit_fb_match *match, 275 const struct usb_host_interface *alts) 276{ 277 for (; match->id; match++) 278 if (match->id == chip->usb_id && 279 (!match->iface_class || 280 (alts->desc.bInterfaceClass == match->iface_class))) 281 return match; 282 283 return NULL; 284} 285 286/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk 287 * applies. Returns 1 if a quirk was found. 288 */ 289static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, 290 struct audioformat *fmt, 291 struct usb_host_interface *alts) 292{ 293 const struct snd_usb_implicit_fb_match *p; 294 unsigned int attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; 295 296 p = find_implicit_fb_entry(chip, playback_implicit_fb_quirks, alts); 297 if (p) { 298 switch (p->type) { 299 case IMPLICIT_FB_GENERIC: 300 return add_generic_implicit_fb(chip, fmt, alts); 301 case IMPLICIT_FB_NONE: 302 return 0; /* No quirk */ 303 case IMPLICIT_FB_FIXED: 304 return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0, 305 p->iface, NULL); 306 } 307 } 308 309 /* Special handling for devices with capture quirks */ 310 p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); 311 if (p) { 312 switch (p->type) { 313 case IMPLICIT_FB_FIXED: 314 return 0; /* no quirk */ 315 case IMPLICIT_FB_BOTH: 316 chip->quirk_flags |= QUIRK_FLAG_PLAYBACK_FIRST; 317 return add_generic_implicit_fb(chip, fmt, alts); 318 } 319 } 320 321 /* Generic UAC2 implicit feedback */ 322 if (attr == USB_ENDPOINT_SYNC_ASYNC && 323 alts->desc.bInterfaceClass == USB_CLASS_AUDIO && 324 alts->desc.bInterfaceProtocol == UAC_VERSION_2 && 325 alts->desc.bNumEndpoints == 1) { 326 if (add_generic_uac2_implicit_fb(chip, fmt, 327 alts->desc.bInterfaceNumber + 1, 328 alts->desc.bAlternateSetting)) 329 return 1; 330 } 331 332 /* Roland/BOSS implicit feedback with vendor spec class */ 333 if (USB_ID_VENDOR(chip->usb_id) == 0x0582) { 334 if (add_roland_implicit_fb(chip, fmt, alts) > 0) 335 return 1; 336 } 337 338 /* Pioneer devices with vendor spec class */ 339 if (is_pioneer_implicit_fb(chip, alts)) { 340 chip->quirk_flags |= QUIRK_FLAG_PLAYBACK_FIRST; 341 return add_implicit_fb_sync_ep(chip, fmt, 342 get_endpoint(alts, 1)->bEndpointAddress, 343 1, alts->desc.bInterfaceNumber, 344 alts); 345 } 346 347 /* Try the generic implicit fb if available */ 348 if (chip->generic_implicit_fb || 349 (chip->quirk_flags & QUIRK_FLAG_GENERIC_IMPLICIT_FB)) 350 return add_generic_implicit_fb(chip, fmt, alts); 351 352 /* No quirk */ 353 return 0; 354} 355 356/* same for capture, but only handling FIXED entry */ 357static int audioformat_capture_quirk(struct snd_usb_audio *chip, 358 struct audioformat *fmt, 359 struct usb_host_interface *alts) 360{ 361 const struct snd_usb_implicit_fb_match *p; 362 363 p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); 364 if (p && (p->type == IMPLICIT_FB_FIXED || p->type == IMPLICIT_FB_BOTH)) 365 return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0, 366 p->iface, NULL); 367 368 /* Roland/BOSS need full-duplex streams */ 369 if (USB_ID_VENDOR(chip->usb_id) == 0x0582) { 370 if (add_roland_capture_quirk(chip, fmt, alts) > 0) 371 return 1; 372 } 373 374 if (is_pioneer_implicit_fb(chip, alts)) 375 return 1; /* skip the quirk, also don't handle generic sync EP */ 376 return 0; 377} 378 379/* 380 * Parse altset and set up implicit feedback endpoint on the audioformat 381 */ 382int snd_usb_parse_implicit_fb_quirk(struct snd_usb_audio *chip, 383 struct audioformat *fmt, 384 struct usb_host_interface *alts) 385{ 386 if (chip->quirk_flags & QUIRK_FLAG_SKIP_IMPLICIT_FB) 387 return 0; 388 if (fmt->endpoint & USB_DIR_IN) 389 return audioformat_capture_quirk(chip, fmt, alts); 390 else 391 return audioformat_implicit_fb_quirk(chip, fmt, alts); 392} 393 394/* 395 * Return the score of matching two audioformats. 396 * Veto the audioformat if: 397 * - It has no channels for some reason. 398 * - Requested PCM format is not supported. 399 * - Requested sample rate is not supported. 400 */ 401static int match_endpoint_audioformats(struct snd_usb_substream *subs, 402 const struct audioformat *fp, 403 int rate, int channels, 404 snd_pcm_format_t pcm_format) 405{ 406 int i, score; 407 408 if (fp->channels < 1) 409 return 0; 410 411 if (!(fp->formats & pcm_format_to_bits(pcm_format))) 412 return 0; 413 414 if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { 415 if (rate < fp->rate_min || rate > fp->rate_max) 416 return 0; 417 } else { 418 for (i = 0; i < fp->nr_rates; i++) { 419 if (fp->rate_table[i] == rate) 420 break; 421 } 422 if (i >= fp->nr_rates) 423 return 0; 424 } 425 426 score = 1; 427 if (fp->channels == channels) 428 score++; 429 430 return score; 431} 432 433static struct snd_usb_substream * 434find_matching_substream(struct snd_usb_audio *chip, int stream, int ep_num, 435 int fmt_type) 436{ 437 struct snd_usb_stream *as; 438 struct snd_usb_substream *subs; 439 440 list_for_each_entry(as, &chip->pcm_list, list) { 441 subs = &as->substream[stream]; 442 if (as->fmt_type == fmt_type && subs->ep_num == ep_num) 443 return subs; 444 } 445 446 return NULL; 447} 448 449/* 450 * Return the audioformat that is suitable for the implicit fb 451 */ 452const struct audioformat * 453snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, 454 const struct audioformat *target, 455 const struct snd_pcm_hw_params *params, 456 int stream) 457{ 458 struct snd_usb_substream *subs; 459 const struct audioformat *fp, *sync_fmt = NULL; 460 int score, high_score; 461 462 /* Use the original audioformat as fallback for the shared altset */ 463 if (target->iface == target->sync_iface && 464 target->altsetting == target->sync_altsetting) 465 sync_fmt = target; 466 467 subs = find_matching_substream(chip, stream, target->sync_ep, 468 target->fmt_type); 469 if (!subs) 470 return sync_fmt; 471 472 high_score = 0; 473 list_for_each_entry(fp, &subs->fmt_list, list) { 474 score = match_endpoint_audioformats(subs, fp, 475 params_rate(params), 476 params_channels(params), 477 params_format(params)); 478 if (score > high_score) { 479 sync_fmt = fp; 480 high_score = score; 481 } 482 } 483 484 return sync_fmt; 485} 486