/* 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) return0;
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)) return0; /* 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) return0;
/* 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) return0;
/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk *applies.Returns1ifaquirkwasfound.
*/ 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: return0; /* 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: return0; /* 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) return1;
}
/* 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 */ return0;
}
/* 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;
/* *Returnthescoreofmatchingtwoaudioformats. *Vetotheaudioformatif: *-Ithasnochannelsforsomereason. *-RequestedPCMformatisnotsupported. *-Requestedsamplerateisnotsupported.
*/ 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) return0;
if (!(fp->formats & pcm_format_to_bits(pcm_format))) return0;
if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { if (rate < fp->rate_min || rate > fp->rate_max) return0;
} else { for (i = 0; i < fp->nr_rates; i++) { if (fp->rate_table[i] == rate) break;
} if (i >= fp->nr_rates) return0;
}
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;
/* 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.