/* Implicit feedback quirk table for capture: only FIXED type */ staticconststruct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = {
{} /* terminator */
};
/* set up sync EP information on the audioformat */ staticint add_implicit_fb_sync_ep(struct snd_usb_audio *chip, struct audioformat *fmt, int ep, int ep_idx, int ifnum, conststruct usb_host_interface *alts)
{ struct usb_interface *iface;
if (!alts) {
iface = usb_ifnum_to_if(chip->dev, ifnum); if (!iface || iface->num_altsetting < 2) return 0;
alts = &iface->altsetting[1];
}
/* Like the UAC2 case above, but specific to Roland with vendor class and hack */ staticint add_roland_implicit_fb(struct snd_usb_audio *chip, struct audioformat *fmt, struct usb_host_interface *alts)
{ struct usb_endpoint_descriptor *epd;
if (!roland_sanity_check_iface(alts)) return 0; /* only when both streams are with ASYNC type */
epd = get_endpoint(alts, 0); if (!usb_endpoint_is_isoc_out(epd) ||
(epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) return 0;
/* Playback and capture EPs on Pioneer devices share the same iface/altset * for the implicit feedback operation
*/ staticbool is_pioneer_implicit_fb(struct snd_usb_audio *chip, struct usb_host_interface *alts)
{ struct usb_endpoint_descriptor *epd;
if (USB_ID_VENDOR(chip->usb_id) != 0x2b73 &&
USB_ID_VENDOR(chip->usb_id) != 0x08e4) returnfalse; if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) returnfalse; if (alts->desc.bNumEndpoints != 2) returnfalse;
/* More generic quirk: look for the sync EP next to the data EP */ staticint add_generic_implicit_fb(struct snd_usb_audio *chip, struct audioformat *fmt, struct usb_host_interface *alts)
{ if ((fmt->ep_attr & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) return 0;
/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk * applies. Returns 1 if a quirk was found.
*/ staticint audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, struct audioformat *fmt, struct usb_host_interface *alts)
{ conststruct snd_usb_implicit_fb_match *p; unsignedint attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
p = find_implicit_fb_entry(chip, playback_implicit_fb_quirks, alts); if (p) { switch (p->type) { case IMPLICIT_FB_GENERIC: return add_generic_implicit_fb(chip, fmt, alts); case IMPLICIT_FB_NONE: return 0; /* No quirk */ case IMPLICIT_FB_FIXED: return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0,
p->iface, NULL);
}
}
/* Special handling for devices with capture quirks */
p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); if (p) { switch (p->type) { case IMPLICIT_FB_FIXED: return 0; /* no quirk */ case IMPLICIT_FB_BOTH:
chip->quirk_flags |= QUIRK_FLAG_PLAYBACK_FIRST; return add_generic_implicit_fb(chip, fmt, alts);
}
}
/* Roland/BOSS implicit feedback with vendor spec class */ if (USB_ID_VENDOR(chip->usb_id) == 0x0582) { if (add_roland_implicit_fb(chip, fmt, alts) > 0) return 1;
}
/* Pioneer devices with vendor spec class */ if (is_pioneer_implicit_fb(chip, alts)) {
chip->quirk_flags |= QUIRK_FLAG_PLAYBACK_FIRST; return add_implicit_fb_sync_ep(chip, fmt,
get_endpoint(alts, 1)->bEndpointAddress,
1, alts->desc.bInterfaceNumber,
alts);
}
/* Try the generic implicit fb if available */ if (chip->generic_implicit_fb ||
(chip->quirk_flags & QUIRK_FLAG_GENERIC_IMPLICIT_FB)) return add_generic_implicit_fb(chip, fmt, alts);
/* No quirk */ return 0;
}
/* same for capture, but only handling FIXED entry */ staticint audioformat_capture_quirk(struct snd_usb_audio *chip, struct audioformat *fmt, struct usb_host_interface *alts)
{ conststruct snd_usb_implicit_fb_match *p;
/* Roland/BOSS need full-duplex streams */ if (USB_ID_VENDOR(chip->usb_id) == 0x0582) { if (add_roland_capture_quirk(chip, fmt, alts) > 0) return 1;
}
if (is_pioneer_implicit_fb(chip, alts)) return 1; /* skip the quirk, also don't handle generic sync EP */ return 0;
}
/* * Parse altset and set up implicit feedback endpoint on the audioformat
*/ int snd_usb_parse_implicit_fb_quirk(struct snd_usb_audio *chip, struct audioformat *fmt, struct usb_host_interface *alts)
{ if (chip->quirk_flags & QUIRK_FLAG_SKIP_IMPLICIT_FB) return 0; if (fmt->endpoint & USB_DIR_IN) return audioformat_capture_quirk(chip, fmt, alts); else return audioformat_implicit_fb_quirk(chip, fmt, alts);
}
/* * Return the score of matching two audioformats. * Veto the audioformat if: * - It has no channels for some reason. * - Requested PCM format is not supported. * - Requested sample rate is not supported.
*/ staticint match_endpoint_audioformats(struct snd_usb_substream *subs, conststruct audioformat *fp, int rate, int channels,
snd_pcm_format_t pcm_format)
{ int i, score;
if (fp->channels < 1) return 0;
if (!(fp->formats & pcm_format_to_bits(pcm_format))) return 0;
if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { if (rate < fp->rate_min || rate > fp->rate_max) return 0;
} else { for (i = 0; i < fp->nr_rates; i++) { if (fp->rate_table[i] == rate) break;
} if (i >= fp->nr_rates) return 0;
}
score = 1; if (fp->channels == channels)
score++;
return score;
}
staticstruct snd_usb_substream *
find_matching_substream(struct snd_usb_audio *chip, int stream, int ep_num, int fmt_type)
{ struct snd_usb_stream *as; struct snd_usb_substream *subs;
/* * Return the audioformat that is suitable for the implicit fb
*/ conststruct audioformat *
snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, conststruct audioformat *target, conststruct snd_pcm_hw_params *params, int stream, bool *fixed_rate)
{ struct snd_usb_substream *subs; conststruct audioformat *fp, *sync_fmt = NULL; int score, high_score;
/* Use the original audioformat as fallback for the shared altset */ if (target->iface == target->sync_iface &&
target->altsetting == target->sync_altsetting)
sync_fmt = target;
subs = find_matching_substream(chip, stream, target->sync_ep,
target->fmt_type); if (!subs) goto end;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.