Update Linux to v5.10.109
Sourced from [1]
[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz
Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/sound/usb/card.c b/sound/usb/card.c
index c2dd18c..45fc217 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -72,8 +72,10 @@ static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
static bool ignore_ctl_error;
static bool autoclock = true;
static char *quirk_alias[SNDRV_CARDS];
+static char *delayed_register[SNDRV_CARDS];
bool snd_usb_use_vmalloc = true;
+bool snd_usb_skip_validation;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -94,8 +96,12 @@ module_param(autoclock, bool, 0444);
MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes).");
module_param_array(quirk_alias, charp, NULL, 0444);
MODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef.");
+module_param_array(delayed_register, charp, NULL, 0444);
+MODULE_PARM_DESC(delayed_register, "Quirk for delayed registration, given by id:iface, e.g. 0123abcd:4.");
module_param_named(use_vmalloc, snd_usb_use_vmalloc, bool, 0444);
MODULE_PARM_DESC(use_vmalloc, "Use vmalloc for PCM intermediate buffers (default: yes).");
+module_param_named(skip_validation, snd_usb_skip_validation, bool, 0444);
+MODULE_PARM_DESC(skip_validation, "Skip unit descriptor validation (default: no).");
/*
* we keep the snd_usb_audio_t instances by ourselves for merging
@@ -224,7 +230,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
dev_warn(&dev->dev,
"unknown interface protocol %#02x, assuming v1\n",
protocol);
- /* fall through */
+ fallthrough;
case UAC_VERSION_1: {
struct uac1_ac_header_descriptor *h1;
@@ -327,6 +333,113 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
}
/*
+ * Profile name preset table
+ */
+struct usb_audio_device_name {
+ u32 id;
+ const char *vendor_name;
+ const char *product_name;
+ const char *profile_name; /* override card->longname */
+};
+
+#define PROFILE_NAME(vid, pid, vendor, product, profile) \
+ { .id = USB_ID(vid, pid), .vendor_name = (vendor), \
+ .product_name = (product), .profile_name = (profile) }
+#define DEVICE_NAME(vid, pid, vendor, product) \
+ PROFILE_NAME(vid, pid, vendor, product, NULL)
+
+/* vendor/product and profile name presets, sorted in device id order */
+static const struct usb_audio_device_name usb_audio_names[] = {
+ /* HP Thunderbolt Dock Audio Headset */
+ PROFILE_NAME(0x03f0, 0x0269, "HP", "Thunderbolt Dock Audio Headset",
+ "HP-Thunderbolt-Dock-Audio-Headset"),
+ /* HP Thunderbolt Dock Audio Module */
+ PROFILE_NAME(0x03f0, 0x0567, "HP", "Thunderbolt Dock Audio Module",
+ "HP-Thunderbolt-Dock-Audio-Module"),
+
+ /* Two entries for Gigabyte TRX40 Aorus Master:
+ * TRX40 Aorus Master has two USB-audio devices, one for the front
+ * headphone with ESS SABRE9218 DAC chip, while another for the rest
+ * I/O (the rear panel and the front mic) with Realtek ALC1220-VB.
+ * Here we provide two distinct names for making UCM profiles easier.
+ */
+ PROFILE_NAME(0x0414, 0xa000, "Gigabyte", "Aorus Master Front Headphone",
+ "Gigabyte-Aorus-Master-Front-Headphone"),
+ PROFILE_NAME(0x0414, 0xa001, "Gigabyte", "Aorus Master Main Audio",
+ "Gigabyte-Aorus-Master-Main-Audio"),
+
+ /* Gigabyte TRX40 Aorus Pro WiFi */
+ PROFILE_NAME(0x0414, 0xa002,
+ "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
+
+ /* Creative/E-Mu devices */
+ DEVICE_NAME(0x041e, 0x3010, "Creative Labs", "Sound Blaster MP3+"),
+ /* Creative/Toshiba Multimedia Center SB-0500 */
+ DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"),
+
+ DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
+
+ /* ASUS ROG Strix */
+ PROFILE_NAME(0x0b05, 0x1917,
+ "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
+ /* ASUS PRIME TRX40 PRO-S */
+ PROFILE_NAME(0x0b05, 0x1918,
+ "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
+
+ /* Dell WD15 Dock */
+ PROFILE_NAME(0x0bda, 0x4014, "Dell", "WD15 Dock", "Dell-WD15-Dock"),
+ /* Dell WD19 Dock */
+ PROFILE_NAME(0x0bda, 0x402e, "Dell", "WD19 Dock", "Dell-WD15-Dock"),
+
+ DEVICE_NAME(0x0ccd, 0x0028, "TerraTec", "Aureon5.1MkII"),
+
+ /*
+ * The original product_name is "USB Sound Device", however this name
+ * is also used by the CM106 based cards, so make it unique.
+ */
+ DEVICE_NAME(0x0d8c, 0x0102, NULL, "ICUSBAUDIO7D"),
+ DEVICE_NAME(0x0d8c, 0x0103, NULL, "Audio Advantage MicroII"),
+
+ /* MSI TRX40 Creator */
+ PROFILE_NAME(0x0db0, 0x0d64,
+ "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
+ /* MSI TRX40 */
+ PROFILE_NAME(0x0db0, 0x543d,
+ "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
+
+ /* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */
+ DEVICE_NAME(0x103d, 0x0100, "Stanton", "ScratchAmp"),
+ DEVICE_NAME(0x103d, 0x0101, "Stanton", "ScratchAmp"),
+
+ /* aka. Serato Scratch Live DJ Box */
+ DEVICE_NAME(0x13e5, 0x0001, "Rane", "SL-1"),
+
+ /* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */
+ PROFILE_NAME(0x17aa, 0x1046, "Lenovo", "ThinkStation P620 Rear",
+ "Lenovo-ThinkStation-P620-Rear"),
+ /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */
+ PROFILE_NAME(0x17aa, 0x104d, "Lenovo", "ThinkStation P620 Main",
+ "Lenovo-ThinkStation-P620-Main"),
+
+ /* Asrock TRX40 Creator */
+ PROFILE_NAME(0x26ce, 0x0a01,
+ "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
+
+ { } /* terminator */
+};
+
+static const struct usb_audio_device_name *
+lookup_device_name(u32 id)
+{
+ static const struct usb_audio_device_name *p;
+
+ for (p = usb_audio_names; p->id; p++)
+ if (p->id == id)
+ return p;
+ return NULL;
+}
+
+/*
* free the chip instance
*
* here we have to do not much, since pcm and controls are already freed
@@ -351,10 +464,16 @@ static void usb_audio_make_shortname(struct usb_device *dev,
const struct snd_usb_audio_quirk *quirk)
{
struct snd_card *card = chip->card;
+ const struct usb_audio_device_name *preset;
+ const char *s = NULL;
- if (quirk && quirk->product_name && *quirk->product_name) {
- strlcpy(card->shortname, quirk->product_name,
- sizeof(card->shortname));
+ preset = lookup_device_name(chip->usb_id);
+ if (preset && preset->product_name)
+ s = preset->product_name;
+ else if (quirk && quirk->product_name)
+ s = quirk->product_name;
+ if (s && *s) {
+ strlcpy(card->shortname, s, sizeof(card->shortname));
return;
}
@@ -376,17 +495,26 @@ static void usb_audio_make_longname(struct usb_device *dev,
const struct snd_usb_audio_quirk *quirk)
{
struct snd_card *card = chip->card;
+ const struct usb_audio_device_name *preset;
+ const char *s = NULL;
int len;
+ preset = lookup_device_name(chip->usb_id);
+
/* shortcut - if any pre-defined string is given, use it */
- if (quirk && quirk->profile_name && *quirk->profile_name) {
- strlcpy(card->longname, quirk->profile_name,
- sizeof(card->longname));
+ if (preset && preset->profile_name)
+ s = preset->profile_name;
+ if (s && *s) {
+ strlcpy(card->longname, s, sizeof(card->longname));
return;
}
- if (quirk && quirk->vendor_name && *quirk->vendor_name) {
- len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname));
+ if (preset && preset->vendor_name)
+ s = preset->vendor_name;
+ else if (quirk && quirk->vendor_name)
+ s = quirk->vendor_name;
+ if (s && *s) {
+ len = strlcpy(card->longname, s, sizeof(card->longname));
} else {
/* retrieve the vendor and device strings as longname */
if (dev->descriptor.iManufacturer)
@@ -522,6 +650,21 @@ static bool get_alias_id(struct usb_device *dev, unsigned int *id)
return false;
}
+static bool check_delayed_register_option(struct snd_usb_audio *chip, int iface)
+{
+ int i;
+ unsigned int id, inum;
+
+ for (i = 0; i < ARRAY_SIZE(delayed_register); i++) {
+ if (delayed_register[i] &&
+ sscanf(delayed_register[i], "%x:%x", &id, &inum) == 2 &&
+ id == chip->usb_id)
+ return inum != iface;
+ }
+
+ return false;
+}
+
static const struct usb_device_id usb_audio_ids[]; /* defined below */
/* look for the corresponding quirk */
@@ -613,7 +756,6 @@ static int usb_audio_probe(struct usb_interface *intf,
id, &chip);
if (err < 0)
goto __error;
- chip->pm_intf = intf;
break;
} else if (vid[i] != -1 || pid[i] != -1) {
dev_info(&dev->dev,
@@ -630,6 +772,13 @@ static int usb_audio_probe(struct usb_interface *intf,
goto __error;
}
}
+
+ if (chip->num_interfaces >= MAX_CARD_INTERFACES) {
+ dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n");
+ err = -EINVAL;
+ goto __error;
+ }
+
dev_set_drvdata(&dev->dev, chip);
/*
@@ -659,10 +808,18 @@ static int usb_audio_probe(struct usb_interface *intf,
goto __error;
}
+ if (chip->need_delayed_register) {
+ dev_info(&dev->dev,
+ "Found post-registration device assignment: %08x:%02x\n",
+ chip->usb_id, ifnum);
+ chip->need_delayed_register = false; /* clear again */
+ }
+
/* we are allowed to call snd_card_register() many times, but first
* check to see if a device needs to skip it or do anything special
*/
- if (!snd_usb_registration_quirk(chip, ifnum)) {
+ if (!snd_usb_registration_quirk(chip, ifnum) &&
+ !check_delayed_register_option(chip, ifnum)) {
err = snd_card_register(chip->card);
if (err < 0)
goto __error;
@@ -673,7 +830,11 @@ static int usb_audio_probe(struct usb_interface *intf,
snd_media_device_create(chip, intf);
}
+ if (quirk)
+ chip->quirk_type = quirk->type;
+
usb_chip[chip->index] = chip;
+ chip->intf[chip->num_interfaces] = intf;
chip->num_interfaces++;
usb_set_intfdata(intf, chip);
atomic_dec(&chip->active);
@@ -746,6 +907,9 @@ static void usb_audio_disconnect(struct usb_interface *intf)
}
}
+ if (chip->quirk_type == QUIRK_SETUP_DISABLE_AUTOSUSPEND)
+ usb_enable_autosuspend(interface_to_usbdev(intf));
+
chip->num_interfaces--;
if (chip->num_interfaces <= 0) {
usb_chip[chip->index] = NULL;
@@ -789,19 +953,37 @@ void snd_usb_unlock_shutdown(struct snd_usb_audio *chip)
int snd_usb_autoresume(struct snd_usb_audio *chip)
{
+ int i, err;
+
if (atomic_read(&chip->shutdown))
return -EIO;
- if (atomic_inc_return(&chip->active) == 1)
- return usb_autopm_get_interface(chip->pm_intf);
+ if (atomic_inc_return(&chip->active) != 1)
+ return 0;
+
+ for (i = 0; i < chip->num_interfaces; i++) {
+ err = usb_autopm_get_interface(chip->intf[i]);
+ if (err < 0) {
+ /* rollback */
+ while (--i >= 0)
+ usb_autopm_put_interface(chip->intf[i]);
+ atomic_dec(&chip->active);
+ return err;
+ }
+ }
return 0;
}
void snd_usb_autosuspend(struct snd_usb_audio *chip)
{
+ int i;
+
if (atomic_read(&chip->shutdown))
return;
- if (atomic_dec_and_test(&chip->active))
- usb_autopm_put_interface(chip->pm_intf);
+ if (!atomic_dec_and_test(&chip->active))
+ return;
+
+ for (i = 0; i < chip->num_interfaces; i++)
+ usb_autopm_put_interface(chip->intf[i]);
}
static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)