brintos

brintos / linux-shallow public Read only

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