ALSA: usb-audio: Introduce quirk_flags field

As more and more device-specific workarounds came up and gathered in
various places, it becomes harder to manage.  Now it's time to clean
up and collect workarounds more consistently and make them more easily
applicable.

This patch is the first step for that: a new field quirk_flags is
introduced in snd_usb_audio struct to contain the bit flags for
various device-specific quirks.  Those are separate one from the
quirks in quirks-table.h; the quirks-table.h entries are for more
intrusive stuff that needs the descriptor override, while the new
quirk_flags is for easier ones that are tied with the vendor:product
IDs.

In this patch, as the first example, we convert the list of devices
and vendors to ignore GET_SAMPLE_RATE, formerly defined in
snb_usb_get_sample_rate_quirk().

Link: https://lore.kernel.org/r/20210729073855.19043-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2021-07-29 09:38:47 +02:00
parent 01099b1ad9
commit 4d4dee0aef
5 changed files with 84 additions and 34 deletions

View File

@ -610,6 +610,8 @@ static int snd_usb_audio_create(struct usb_interface *intf,
INIT_LIST_HEAD(&chip->midi_list);
INIT_LIST_HEAD(&chip->mixer_list);
snd_usb_init_quirk_flags(chip);
card->private_free = snd_usb_audio_free;
strcpy(card->driver, "USB-Audio");
@ -789,7 +791,6 @@ static int usb_audio_probe(struct usb_interface *intf,
if (!chip->ctrl_intf)
chip->ctrl_intf = alts;
chip->txfr_quirk = 0;
err = 1; /* continue */
if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
/* need some special handlings */

View File

@ -426,7 +426,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip,
/* Don't check the sample rate for devices which we know don't
* support reading */
if (snd_usb_get_sample_rate_quirk(chip))
if (chip->quirk_flags & QUIRK_FLAG_GET_SAMPLE_RATE)
return 0;
/* the firmware is likely buggy, don't repeat to fail too many times */
if (chip->sample_rate_read_error > 2)

View File

@ -1518,36 +1518,6 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
}
}
bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
{
/* devices which do not support reading the sample rate. */
switch (chip->usb_id) {
case USB_ID(0x041e, 0x4080): /* Creative Live Cam VF0610 */
case USB_ID(0x04d8, 0xfeea): /* Benchmark DAC1 Pre */
case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
case USB_ID(0x05a3, 0x9420): /* ELP HD USB Camera */
case USB_ID(0x05a7, 0x1020): /* Bose Companion 5 */
case USB_ID(0x074d, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */
case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */
case USB_ID(0x046d, 0x084c): /* Logitech ConferenceCam Connect */
return true;
}
/* devices of these vendors don't support reading rate, either */
switch (USB_ID_VENDOR(chip->usb_id)) {
case 0x045e: /* MS Lifecam */
case 0x047f: /* Plantronics */
case 0x1de7: /* Phoenix Audio */
return true;
}
return false;
}
/* ITF-USB DSD based DACs need a vendor cmd to switch
* between PCM and native DSD mode
*/
@ -1916,3 +1886,71 @@ bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface)
/* Register as normal */
return false;
}
/*
* driver behavior quirk flags
*/
struct usb_audio_quirk_flags_table {
u32 id;
u32 flags;
};
#define DEVICE_FLG(vid, pid, _flags) \
{ .id = USB_ID(vid, pid), .flags = (_flags) }
#define VENDOR_FLG(vid, _flags) DEVICE_FLG(vid, 0, _flags)
static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
/* Device matches */
DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x046d, 0x084c, /* Logitech ConferenceCam Connect */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x04d8, 0xfeea, /* Benchmark DAC1 Pre */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x0556, 0x0014, /* Phoenix Audio TMX320VC */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x05a3, 0x9420, /* ELP HD USB Camera */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x05a7, 0x1020, /* Bose Companion 5 */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x074d, 0x3553, /* Outlaw RR2150 (Micronas UAC3553B) */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x1901, 0x0191, /* GE B850V3 CP2114 audio interface */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x21b4, 0x0081, /* AudioQuest DragonFly */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
QUIRK_FLAG_GET_SAMPLE_RATE),
/* Vendor matches */
VENDOR_FLG(0x045e, /* MS Lifecam */
QUIRK_FLAG_GET_SAMPLE_RATE),
VENDOR_FLG(0x047f, /* Plantronics */
QUIRK_FLAG_GET_SAMPLE_RATE),
VENDOR_FLG(0x1de7, /* Phoenix Audio */
QUIRK_FLAG_GET_SAMPLE_RATE),
{} /* terminator */
};
void snd_usb_init_quirk_flags(struct snd_usb_audio *chip)
{
const struct usb_audio_quirk_flags_table *p;
for (p = quirk_flags_table; p->id; p++) {
if (chip->usb_id == p->id ||
(!USB_ID_PRODUCT(p->id) &&
USB_ID_VENDOR(chip->usb_id) == USB_ID_VENDOR(p->id))) {
usb_audio_dbg(chip,
"Set quirk_flags 0x%x for device %04x:%04x\n",
p->flags, USB_ID_VENDOR(chip->usb_id),
USB_ID_PRODUCT(chip->usb_id));
chip->quirk_flags |= p->flags;
return;
}
}
}

View File

@ -28,8 +28,6 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev,
void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
const struct audioformat *fmt);
bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip);
int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
const struct audioformat *fp);
@ -53,4 +51,6 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface);
void snd_usb_init_quirk_flags(struct snd_usb_audio *chip);
#endif /* __USBAUDIO_QUIRKS_H */

View File

@ -34,6 +34,7 @@ struct snd_usb_audio {
atomic_t shutdown;
atomic_t usage_count;
wait_queue_head_t shutdown_wait;
unsigned int quirk_flags;
unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
unsigned int tx_length_quirk:1; /* Put length specifier in transfers */
unsigned int need_delayed_register:1; /* warn for delayed registration */
@ -129,4 +130,14 @@ void snd_usb_unlock_shutdown(struct snd_usb_audio *chip);
extern bool snd_usb_use_vmalloc;
extern bool snd_usb_skip_validation;
/*
* Driver behavior quirk flags, stored in chip->quirk_flags
*
* QUIRK_FLAG_GET_SAMPLE_RATE:
* Skip reading sample rate for devices, as some devices behave inconsistently
* or return error
*/
#define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0)
#endif /* __USBAUDIO_H */