Skip to content

Commit

Permalink
Merge tag 'sound-5.15-rc6' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "This contains quite a few device-specific fixes for usual HD- and
  USB-audio in addition to a couple of ALSA core fixes (a UAF fix in
  sequencer and a fix for a misplaced PCM 32bit compat ioctl).

  Nothing really stands out"

* tag 'sound-5.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: usb-audio: Add quirk for VF0770
  ALSA: hda: avoid write to STATESTS if controller is in reset
  ALSA: hda/realtek: Fix the mic type detection issue for ASUS G551JW
  ALSA: pcm: Workaround for a wrong offset in SYNC_PTR compat ioctl
  ALSA: hda/realtek: Fix for quirk to enable speaker output on the Lenovo 13s Gen2
  ALSA: hda: intel: Allow repeatedly probing on codec configuration errors
  ALSA: hda/realtek: Add quirk for TongFang PHxTxX1
  ALSA: hda/realtek - ALC236 headset MIC recording issue
  ALSA: usb-audio: Enable rate validation for Scarlett devices
  ALSA: hda/realtek: Add quirk for Clevo X170KM-G
  ALSA: hda/realtek: Complete partial device name to avoid ambiguity
  ALSA: hda - Enable headphone mic on Dell Latitude laptops with ALC3254
  ALSA: seq: Fix a potential UAF by wrong private_free call order
  ALSA: hda/realtek: Enable 4-speaker output for Dell Precision 5560 laptop
  ALSA: usb-audio: Fix a missing error check in scarlett gen2 mixer
  • Loading branch information
Linus Torvalds committed Oct 14, 2021
2 parents 348949d + 48827e1 commit 1626d9a
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 37 deletions.
1 change: 1 addition & 0 deletions include/sound/hda_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ struct hda_codec {
#endif

/* misc flags */
unsigned int configured:1; /* codec was configured */
unsigned int in_freeing:1; /* being released */
unsigned int registered:1; /* codec was registered */
unsigned int display_power_control:1; /* needs display power */
Expand Down
72 changes: 71 additions & 1 deletion sound/core/pcm_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,76 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
}
#endif /* CONFIG_X86_X32 */

#ifdef __BIG_ENDIAN
typedef char __pad_before_u32[4];
typedef char __pad_after_u32[0];
#else
typedef char __pad_before_u32[0];
typedef char __pad_after_u32[4];
#endif

/* PCM 2.0.15 API definition had a bug in mmap control; it puts the avail_min
* at the wrong offset due to a typo in padding type.
* The bug hits only 32bit.
* A workaround for incorrect read/write is needed only in 32bit compat mode.
*/
struct __snd_pcm_mmap_control64_buggy {
__pad_before_u32 __pad1;
__u32 appl_ptr;
__pad_before_u32 __pad2; /* SiC! here is the bug */
__pad_before_u32 __pad3;
__u32 avail_min;
__pad_after_uframe __pad4;
};

static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
struct snd_pcm_sync_ptr __user *_sync_ptr)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_sync_ptr sync_ptr;
struct __snd_pcm_mmap_control64_buggy *sync_cp;
volatile struct snd_pcm_mmap_status *status;
volatile struct snd_pcm_mmap_control *control;
int err;

memset(&sync_ptr, 0, sizeof(sync_ptr));
sync_cp = (struct __snd_pcm_mmap_control64_buggy *)&sync_ptr.c.control;
if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
return -EFAULT;
if (copy_from_user(sync_cp, &(_sync_ptr->c.control), sizeof(*sync_cp)))
return -EFAULT;
status = runtime->status;
control = runtime->control;
if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
err = snd_pcm_hwsync(substream);
if (err < 0)
return err;
}
snd_pcm_stream_lock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
if (err < 0) {
snd_pcm_stream_unlock_irq(substream);
return err;
}
} else {
sync_cp->appl_ptr = control->appl_ptr;
}
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = sync_cp->avail_min;
else
sync_cp->avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
return -EFAULT;
return 0;
}

/*
*/
enum {
Expand Down Expand Up @@ -537,7 +607,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
if (in_x32_syscall())
return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
#endif /* CONFIG_X86_X32 */
return snd_pcm_common_ioctl(file, substream, cmd, argp);
return snd_pcm_ioctl_sync_ptr_buggy(substream, argp);
case SNDRV_PCM_IOCTL_HW_REFINE32:
return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
case SNDRV_PCM_IOCTL_HW_PARAMS32:
Expand Down
8 changes: 3 additions & 5 deletions sound/core/seq_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ static int snd_seq_device_dev_free(struct snd_device *device)
struct snd_seq_device *dev = device->device_data;

cancel_autoload_drivers();
if (dev->private_free)
dev->private_free(dev);
put_device(&dev->dev);
return 0;
}
Expand Down Expand Up @@ -183,11 +185,7 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)

static void snd_seq_dev_release(struct device *dev)
{
struct snd_seq_device *sdev = to_seq_dev(dev);

if (sdev->private_free)
sdev->private_free(sdev);
kfree(sdev);
kfree(to_seq_dev(dev));
}

/*
Expand Down
5 changes: 3 additions & 2 deletions sound/hda/hdac_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,9 @@ int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset)
if (!full_reset)
goto skip_reset;

/* clear STATESTS */
snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);
/* clear STATESTS if not in reset */
if (snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)
snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);

/* reset controller */
snd_hdac_bus_enter_link_reset(bus);
Expand Down
20 changes: 11 additions & 9 deletions sound/pci/hda/hda_bind.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,29 +298,31 @@ int snd_hda_codec_configure(struct hda_codec *codec)
{
int err;

if (codec->configured)
return 0;

if (is_generic_config(codec))
codec->probe_id = HDA_CODEC_ID_GENERIC;
else
codec->probe_id = 0;

err = snd_hdac_device_register(&codec->core);
if (err < 0)
return err;
if (!device_is_registered(&codec->core.dev)) {
err = snd_hdac_device_register(&codec->core);
if (err < 0)
return err;
}

if (!codec->preset)
codec_bind_module(codec);
if (!codec->preset) {
err = codec_bind_generic(codec);
if (err < 0) {
codec_err(codec, "Unable to bind the codec\n");
goto error;
codec_dbg(codec, "Unable to bind the codec\n");
return err;
}
}

codec->configured = 1;
return 0;

error:
snd_hdac_device_unregister(&codec->core);
return err;
}
EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
1 change: 1 addition & 0 deletions sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,7 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
snd_array_free(&codec->nids);
remove_conn_list(codec);
snd_hdac_regmap_exit(&codec->core);
codec->configured = 0;
}
EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup_for_unbind);

Expand Down
24 changes: 16 additions & 8 deletions sound/pci/hda/hda_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <sound/core.h>
#include <sound/initval.h>
#include "hda_controller.h"
#include "hda_local.h"

#define CREATE_TRACE_POINTS
#include "hda_controller_trace.h"
Expand Down Expand Up @@ -1248,17 +1249,24 @@ EXPORT_SYMBOL_GPL(azx_probe_codecs);
int azx_codec_configure(struct azx *chip)
{
struct hda_codec *codec, *next;
int success = 0;

/* use _safe version here since snd_hda_codec_configure() deregisters
* the device upon error and deletes itself from the bus list.
*/
list_for_each_codec_safe(codec, next, &chip->bus) {
snd_hda_codec_configure(codec);
list_for_each_codec(codec, &chip->bus) {
if (!snd_hda_codec_configure(codec))
success++;
}

if (!azx_bus(chip)->num_codecs)
return -ENODEV;
return 0;
if (success) {
/* unregister failed codecs if any codec has been probed */
list_for_each_codec_safe(codec, next, &chip->bus) {
if (!codec->configured) {
codec_err(codec, "Unable to configure, disabling\n");
snd_hdac_device_unregister(&codec->core);
}
}
}

return success ? 0 : -ENODEV;
}
EXPORT_SYMBOL_GPL(azx_codec_configure);

Expand Down
2 changes: 1 addition & 1 deletion sound/pci/hda/hda_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
/* 24 unused */
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
/* 27 unused */
#define AZX_DCAPS_RETRY_PROBE (1 << 27) /* retry probe if no codec is configured */
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */
Expand Down
29 changes: 23 additions & 6 deletions sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,8 @@ enum {
/* quirks for AMD SB */
#define AZX_DCAPS_PRESET_AMD_SB \
(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_AMD_WORKAROUND |\
AZX_DCAPS_SNOOP_TYPE(ATI) | AZX_DCAPS_PM_RUNTIME)
AZX_DCAPS_SNOOP_TYPE(ATI) | AZX_DCAPS_PM_RUNTIME |\
AZX_DCAPS_RETRY_PROBE)

/* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA \
Expand Down Expand Up @@ -1723,7 +1724,7 @@ static void azx_check_snoop_available(struct azx *chip)

static void azx_probe_work(struct work_struct *work)
{
struct hda_intel *hda = container_of(work, struct hda_intel, probe_work);
struct hda_intel *hda = container_of(work, struct hda_intel, probe_work.work);
azx_probe_continue(&hda->chip);
}

Expand Down Expand Up @@ -1828,7 +1829,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
}

/* continue probing in work context as may trigger request module */
INIT_WORK(&hda->probe_work, azx_probe_work);
INIT_DELAYED_WORK(&hda->probe_work, azx_probe_work);

*rchip = chip;

Expand Down Expand Up @@ -2142,7 +2143,7 @@ static int azx_probe(struct pci_dev *pci,
#endif

if (schedule_probe)
schedule_work(&hda->probe_work);
schedule_delayed_work(&hda->probe_work, 0);

dev++;
if (chip->disabled)
Expand Down Expand Up @@ -2228,6 +2229,11 @@ static int azx_probe_continue(struct azx *chip)
int dev = chip->dev_index;
int err;

if (chip->disabled || hda->init_failed)
return -EIO;
if (hda->probe_retry)
goto probe_retry;

to_hda_bus(bus)->bus_probing = 1;
hda->probe_continued = 1;

Expand Down Expand Up @@ -2289,10 +2295,20 @@ static int azx_probe_continue(struct azx *chip)
#endif
}
#endif

probe_retry:
if (bus->codec_mask && !(probe_only[dev] & 1)) {
err = azx_codec_configure(chip);
if (err < 0)
if (err) {
if ((chip->driver_caps & AZX_DCAPS_RETRY_PROBE) &&
++hda->probe_retry < 60) {
schedule_delayed_work(&hda->probe_work,
msecs_to_jiffies(1000));
return 0; /* keep things up */
}
dev_err(chip->card->dev, "Cannot probe codecs, giving up\n");
goto out_free;
}
}

err = snd_card_register(chip->card);
Expand Down Expand Up @@ -2322,6 +2338,7 @@ static int azx_probe_continue(struct azx *chip)
display_power(chip, false);
complete_all(&hda->probe_wait);
to_hda_bus(bus)->bus_probing = 0;
hda->probe_retry = 0;
return 0;
}

Expand All @@ -2347,7 +2364,7 @@ static void azx_remove(struct pci_dev *pci)
* device during cancel_work_sync() call.
*/
device_unlock(&pci->dev);
cancel_work_sync(&hda->probe_work);
cancel_delayed_work_sync(&hda->probe_work);
device_lock(&pci->dev);

snd_card_free(card);
Expand Down
4 changes: 3 additions & 1 deletion sound/pci/hda/hda_intel.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct hda_intel {

/* sync probing */
struct completion probe_wait;
struct work_struct probe_work;
struct delayed_work probe_work;

/* card list (for power_save trigger) */
struct list_head list;
Expand All @@ -30,6 +30,8 @@ struct hda_intel {
unsigned int freed:1; /* resources already released */

bool need_i915_power:1; /* the hda controller needs i915 power */

int probe_retry; /* being probe-retry */
};

#endif
Loading

0 comments on commit 1626d9a

Please sign in to comment.