Commit 484faec8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-5.14-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "A collection of small fixes:

   - A few regression fixes (PCM core fixes, USB-audio fixes)

   - Follow up fixes for the USB-audio mixer changes in this cycle

   - A long-standing ALSA sequencer race bug fix

   - Usual device-specific quirks for HD- and USB-audio"

* tag 'sound-5.14-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: seq: Fix racy deletion of subscriber
  ALSA: memalloc: Fix regression with SNDRV_DMA_TYPE_CONTINUOUS
  ALSA: pcm - fix mmap capability check for the snd-dummy driver
  ALSA: usb-audio: Avoid unnecessary or invalid connector selection at resume
  ALSA: hda/realtek: add mic quirk for Acer SF314-42
  ALSA: usb-audio: Add registration quirk for JBL Quantum 600
  ALSA: hda/realtek: Fix headset mic for Acer SWIFT SF314-56 (ALC256)
  ALSA: usb-audio: Fix superfluous autosuspend recovery
  ALSA: usb-audio: fix incorrect clock source setting
  ALSA: scarlett2: Fix line out/speaker switching notifications
  ALSA: scarlett2: Correct channel mute status after mute button pressed
  ALSA: scarlett2: Fix Direct Monitor control name for 2i2
  ALSA: scarlett2: Fix Mute/Dim/MSD Mode control names
parents 1254f05c 97367c97
...@@ -215,7 +215,7 @@ static int snd_dma_continuous_mmap(struct snd_dma_buffer *dmab, ...@@ -215,7 +215,7 @@ static int snd_dma_continuous_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area) struct vm_area_struct *area)
{ {
return remap_pfn_range(area, area->vm_start, return remap_pfn_range(area, area->vm_start,
dmab->addr >> PAGE_SHIFT, page_to_pfn(virt_to_page(dmab->area)),
area->vm_end - area->vm_start, area->vm_end - area->vm_start,
area->vm_page_prot); area->vm_page_prot);
} }
......
...@@ -246,7 +246,7 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream) ...@@ -246,7 +246,7 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream)
if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP)) if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
return false; return false;
if (substream->ops->mmap) if (substream->ops->mmap || substream->ops->page)
return true; return true;
switch (substream->dma_buffer.dev.type) { switch (substream->dma_buffer.dev.type) {
......
...@@ -514,10 +514,11 @@ static int check_and_subscribe_port(struct snd_seq_client *client, ...@@ -514,10 +514,11 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
return err; return err;
} }
static void delete_and_unsubscribe_port(struct snd_seq_client *client, /* called with grp->list_mutex held */
struct snd_seq_client_port *port, static void __delete_and_unsubscribe_port(struct snd_seq_client *client,
struct snd_seq_subscribers *subs, struct snd_seq_client_port *port,
bool is_src, bool ack) struct snd_seq_subscribers *subs,
bool is_src, bool ack)
{ {
struct snd_seq_port_subs_info *grp; struct snd_seq_port_subs_info *grp;
struct list_head *list; struct list_head *list;
...@@ -525,7 +526,6 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client, ...@@ -525,7 +526,6 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
grp = is_src ? &port->c_src : &port->c_dest; grp = is_src ? &port->c_src : &port->c_dest;
list = is_src ? &subs->src_list : &subs->dest_list; list = is_src ? &subs->src_list : &subs->dest_list;
down_write(&grp->list_mutex);
write_lock_irq(&grp->list_lock); write_lock_irq(&grp->list_lock);
empty = list_empty(list); empty = list_empty(list);
if (!empty) if (!empty)
...@@ -535,6 +535,18 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client, ...@@ -535,6 +535,18 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
if (!empty) if (!empty)
unsubscribe_port(client, port, grp, &subs->info, ack); unsubscribe_port(client, port, grp, &subs->info, ack);
}
static void delete_and_unsubscribe_port(struct snd_seq_client *client,
struct snd_seq_client_port *port,
struct snd_seq_subscribers *subs,
bool is_src, bool ack)
{
struct snd_seq_port_subs_info *grp;
grp = is_src ? &port->c_src : &port->c_dest;
down_write(&grp->list_mutex);
__delete_and_unsubscribe_port(client, port, subs, is_src, ack);
up_write(&grp->list_mutex); up_write(&grp->list_mutex);
} }
...@@ -590,27 +602,30 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, ...@@ -590,27 +602,30 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
struct snd_seq_client_port *dest_port, struct snd_seq_client_port *dest_port,
struct snd_seq_port_subscribe *info) struct snd_seq_port_subscribe *info)
{ {
struct snd_seq_port_subs_info *src = &src_port->c_src; struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
struct snd_seq_subscribers *subs; struct snd_seq_subscribers *subs;
int err = -ENOENT; int err = -ENOENT;
down_write(&src->list_mutex); /* always start from deleting the dest port for avoiding concurrent
* deletions
*/
down_write(&dest->list_mutex);
/* look for the connection */ /* look for the connection */
list_for_each_entry(subs, &src->list_head, src_list) { list_for_each_entry(subs, &dest->list_head, dest_list) {
if (match_subs_info(info, &subs->info)) { if (match_subs_info(info, &subs->info)) {
atomic_dec(&subs->ref_count); /* mark as not ready */ __delete_and_unsubscribe_port(dest_client, dest_port,
subs, false,
connector->number != dest_client->number);
err = 0; err = 0;
break; break;
} }
} }
up_write(&src->list_mutex); up_write(&dest->list_mutex);
if (err < 0) if (err < 0)
return err; return err;
delete_and_unsubscribe_port(src_client, src_port, subs, true, delete_and_unsubscribe_port(src_client, src_port, subs, true,
connector->number != src_client->number); connector->number != src_client->number);
delete_and_unsubscribe_port(dest_client, dest_port, subs, false,
connector->number != dest_client->number);
kfree(subs); kfree(subs);
return 0; return 0;
} }
......
...@@ -8274,9 +8274,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -8274,9 +8274,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1300, "Acer SWIFT SF314-56", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1330, "Acer TravelMate X514-51T", ALC255_FIXUP_ACER_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1330, "Acer TravelMate X514-51T", ALC255_FIXUP_ACER_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x142b, "Acer Swift SF314-42", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
......
...@@ -907,7 +907,7 @@ static void usb_audio_disconnect(struct usb_interface *intf) ...@@ -907,7 +907,7 @@ static void usb_audio_disconnect(struct usb_interface *intf)
} }
} }
if (chip->quirk_type & QUIRK_SETUP_DISABLE_AUTOSUSPEND) if (chip->quirk_type == QUIRK_SETUP_DISABLE_AUTOSUSPEND)
usb_enable_autosuspend(interface_to_usbdev(intf)); usb_enable_autosuspend(interface_to_usbdev(intf));
chip->num_interfaces--; chip->num_interfaces--;
......
...@@ -324,6 +324,12 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, ...@@ -324,6 +324,12 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
sources[ret - 1], sources[ret - 1],
visited, validate); visited, validate);
if (ret > 0) { if (ret > 0) {
/*
* For Samsung USBC Headset (AKG), setting clock selector again
* will result in incorrect default clock setting problems
*/
if (chip->usb_id == USB_ID(0x04e8, 0xa051))
return ret;
err = uac_clock_selector_set_val(chip, entity_id, cur); err = uac_clock_selector_set_val(chip, entity_id, cur);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -1816,6 +1816,15 @@ static void get_connector_control_name(struct usb_mixer_interface *mixer, ...@@ -1816,6 +1816,15 @@ static void get_connector_control_name(struct usb_mixer_interface *mixer,
strlcat(name, " - Output Jack", name_size); strlcat(name, " - Output Jack", name_size);
} }
/* get connector value to "wake up" the USB audio */
static int connector_mixer_resume(struct usb_mixer_elem_list *list)
{
struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list);
get_connector_value(cval, NULL, NULL);
return 0;
}
/* Build a mixer control for a UAC connector control (jack-detect) */ /* Build a mixer control for a UAC connector control (jack-detect) */
static void build_connector_control(struct usb_mixer_interface *mixer, static void build_connector_control(struct usb_mixer_interface *mixer,
const struct usbmix_name_map *imap, const struct usbmix_name_map *imap,
...@@ -1833,6 +1842,10 @@ static void build_connector_control(struct usb_mixer_interface *mixer, ...@@ -1833,6 +1842,10 @@ static void build_connector_control(struct usb_mixer_interface *mixer,
if (!cval) if (!cval)
return; return;
snd_usb_mixer_elem_init_std(&cval->head, mixer, term->id); snd_usb_mixer_elem_init_std(&cval->head, mixer, term->id);
/* set up a specific resume callback */
cval->head.resume = connector_mixer_resume;
/* /*
* UAC2: The first byte from reading the UAC2_TE_CONNECTOR control returns the * UAC2: The first byte from reading the UAC2_TE_CONNECTOR control returns the
* number of channels connected. * number of channels connected.
...@@ -3642,23 +3655,15 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list) ...@@ -3642,23 +3655,15 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list)
return 0; return 0;
} }
static int default_mixer_resume(struct usb_mixer_elem_list *list)
{
struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list);
/* get connector value to "wake up" the USB audio */
if (cval->val_type == USB_MIXER_BOOLEAN && cval->channels == 1)
get_connector_value(cval, NULL, NULL);
return 0;
}
static int default_mixer_reset_resume(struct usb_mixer_elem_list *list) static int default_mixer_reset_resume(struct usb_mixer_elem_list *list)
{ {
int err = default_mixer_resume(list); int err;
if (err < 0) if (list->resume) {
return err; err = list->resume(list);
if (err < 0)
return err;
}
return restore_mixer_value(list); return restore_mixer_value(list);
} }
...@@ -3697,7 +3702,7 @@ void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list, ...@@ -3697,7 +3702,7 @@ void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
list->id = unitid; list->id = unitid;
list->dump = snd_usb_mixer_dump_cval; list->dump = snd_usb_mixer_dump_cval;
#ifdef CONFIG_PM #ifdef CONFIG_PM
list->resume = default_mixer_resume; list->resume = NULL;
list->reset_resume = default_mixer_reset_resume; list->reset_resume = default_mixer_reset_resume;
#endif #endif
} }
...@@ -228,7 +228,7 @@ enum { ...@@ -228,7 +228,7 @@ enum {
}; };
static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = { static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = {
"Mute", "Dim" "Mute Playback Switch", "Dim Playback Switch"
}; };
/* Description of each hardware port type: /* Description of each hardware port type:
...@@ -1856,9 +1856,15 @@ static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl, ...@@ -1856,9 +1856,15 @@ static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_elem_info *elem = kctl->private_data;
struct scarlett2_data *private = elem->head.mixer->private_data; struct usb_mixer_interface *mixer = elem->head.mixer;
struct scarlett2_data *private = mixer->private_data;
int index = line_out_remap(private, elem->control); int index = line_out_remap(private, elem->control);
mutex_lock(&private->data_mutex);
if (private->vol_updated)
scarlett2_update_volumes(mixer);
mutex_unlock(&private->data_mutex);
ucontrol->value.integer.value[0] = private->mute_switch[index]; ucontrol->value.integer.value[0] = private->mute_switch[index];
return 0; return 0;
} }
...@@ -1955,10 +1961,12 @@ static void scarlett2_vol_ctl_set_writable(struct usb_mixer_interface *mixer, ...@@ -1955,10 +1961,12 @@ static void scarlett2_vol_ctl_set_writable(struct usb_mixer_interface *mixer,
~SNDRV_CTL_ELEM_ACCESS_WRITE; ~SNDRV_CTL_ELEM_ACCESS_WRITE;
} }
/* Notify of write bit change */ /* Notify of write bit and possible value change */
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, snd_ctl_notify(card,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
&private->vol_ctls[index]->id); &private->vol_ctls[index]->id);
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, snd_ctl_notify(card,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
&private->mute_ctls[index]->id); &private->mute_ctls[index]->id);
} }
...@@ -2530,14 +2538,18 @@ static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer) ...@@ -2530,14 +2538,18 @@ static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer)
{ {
struct scarlett2_data *private = mixer->private_data; struct scarlett2_data *private = mixer->private_data;
const struct scarlett2_device_info *info = private->info; const struct scarlett2_device_info *info = private->info;
const char *s;
if (!info->direct_monitor) if (!info->direct_monitor)
return 0; return 0;
s = info->direct_monitor == 1
? "Direct Monitor Playback Switch"
: "Direct Monitor Playback Enum";
return scarlett2_add_new_ctl( return scarlett2_add_new_ctl(
mixer, &scarlett2_direct_monitor_ctl[info->direct_monitor - 1], mixer, &scarlett2_direct_monitor_ctl[info->direct_monitor - 1],
0, 1, "Direct Monitor Playback Switch", 0, 1, s, &private->direct_monitor_ctl);
&private->direct_monitor_ctl);
} }
/*** Speaker Switching Control ***/ /*** Speaker Switching Control ***/
...@@ -2589,7 +2601,9 @@ static int scarlett2_speaker_switch_enable(struct usb_mixer_interface *mixer) ...@@ -2589,7 +2601,9 @@ static int scarlett2_speaker_switch_enable(struct usb_mixer_interface *mixer)
/* disable the line out SW/HW switch */ /* disable the line out SW/HW switch */
scarlett2_sw_hw_ctl_ro(private, i); scarlett2_sw_hw_ctl_ro(private, i);
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, snd_ctl_notify(card,
SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO,
&private->sw_hw_ctls[i]->id); &private->sw_hw_ctls[i]->id);
} }
...@@ -2913,7 +2927,7 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl, ...@@ -2913,7 +2927,7 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl,
if (private->vol_sw_hw_switch[line_index]) { if (private->vol_sw_hw_switch[line_index]) {
private->mute_switch[line_index] = val; private->mute_switch[line_index] = val;
snd_ctl_notify(mixer->chip->card, snd_ctl_notify(mixer->chip->card,
SNDRV_CTL_EVENT_MASK_INFO, SNDRV_CTL_EVENT_MASK_VALUE,
&private->mute_ctls[i]->id); &private->mute_ctls[i]->id);
} }
} }
...@@ -3455,7 +3469,7 @@ static int scarlett2_add_msd_ctl(struct usb_mixer_interface *mixer) ...@@ -3455,7 +3469,7 @@ static int scarlett2_add_msd_ctl(struct usb_mixer_interface *mixer)
/* Add MSD control */ /* Add MSD control */
return scarlett2_add_new_ctl(mixer, &scarlett2_msd_ctl, return scarlett2_add_new_ctl(mixer, &scarlett2_msd_ctl,
0, 1, "MSD Mode", NULL); 0, 1, "MSD Mode Switch", NULL);
} }
/*** Cleanup/Suspend Callbacks ***/ /*** Cleanup/Suspend Callbacks ***/
......
...@@ -1899,6 +1899,7 @@ static const struct registration_quirk registration_quirks[] = { ...@@ -1899,6 +1899,7 @@ static const struct registration_quirk registration_quirks[] = {
REG_QUIRK_ENTRY(0x0951, 0x16ea, 2), /* Kingston HyperX Cloud Flight S */ REG_QUIRK_ENTRY(0x0951, 0x16ea, 2), /* Kingston HyperX Cloud Flight S */
REG_QUIRK_ENTRY(0x0ecb, 0x1f46, 2), /* JBL Quantum 600 */ REG_QUIRK_ENTRY(0x0ecb, 0x1f46, 2), /* JBL Quantum 600 */
REG_QUIRK_ENTRY(0x0ecb, 0x2039, 2), /* JBL Quantum 400 */ REG_QUIRK_ENTRY(0x0ecb, 0x2039, 2), /* JBL Quantum 400 */
REG_QUIRK_ENTRY(0x0ecb, 0x203c, 2), /* JBL Quantum 600 */
REG_QUIRK_ENTRY(0x0ecb, 0x203e, 2), /* JBL Quantum 800 */ REG_QUIRK_ENTRY(0x0ecb, 0x203e, 2), /* JBL Quantum 800 */
{ 0 } /* terminator */ { 0 } /* terminator */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment