cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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