sound fixes for 7.2-rc1

A collection of small bug fixes accumulated over the last week.
 Most are device-specific fixes while there are a few core fixes as
 well.
 
 Here are the highlights:
 
 ALSA Core:
 - A fix for an uninitialised heap leak in ALSA sequencer core
 - A fix for error handling/resource leak in compress-offload API
 
 USB-audio:
 - A teardown-ordering fix in USB MIDI 2.0 to prevent use-after-free
 - Bounds and length checks for packet data in Native Instruments caiaq
   / Traktor Kontrol input parsers
 - Avoidance of expensive kobject path lookups in DualSense controller
   matches
 - Robustness/memory leak fixes for Qualcomm USB offload driver
 - Focusrite Control Protocol (FCP) NULL-pointer dereference fix and a
   new device quirk (ISA C8X)
 - Device-specific quirks for Yamaha CDS3000 and SC13A
 
 HD-Audio:
 - A bunch of quirks and mute/mic-mute LED fixups for various laptops
   (Acer, Clevo, Lenovo, HP)
 
 ASoC & SoundWire:
 - Avoid failing card registration if the device_link creation fails
 - A workaround for SoundWire randconfig build failures by making
   helper functions static inline
 - Corrected MCLK reference validation for CS530x codecs
 - Clean up of untested, problematic guard() macro replacements in
   Rockchip SAI driver
 - Fix for eDMA maxburst misalignment with channel count in Freescale
   ASRC
 - Miscellaneous hardware-specific fixes (qcom, rt5650, tlv320aic3x,
   tas2781/3)
 
 Others:
 - Bounds and length checks for packet data in Apple iSight
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmo+mnEOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE92VQ/+ItB+EBTpiba9YQYBrzUzq2R3BiNR/EZjU33G
 UMut1zQYQJ53eMmN8yMYc0GMbtk9dCFUAtRGPyQCNEHS6uFw51t3A4wlcXvIu1Sx
 kQqtyaDQ2jp98J72ms4WtN42o29MjcFmhBBcTb3Kw12T+OVTYYneccsGPsHqCXsZ
 RBjJFpDr0Xo1TfnOy9nt/UNUUIMJEtZ1gGlYBqzQgNoLeYH3+dRKBoX2qVAvhIcL
 FJnSGiDgyLpt6uucPAAeIzGHawQXW4ej7XY4S8cLscsB7mY7VEtPFIMx4bN1QYIO
 Ioj2P9KLG4/KYOV8oRQ6kzYTwtO7St9Kd/+xpU5Divjxf6TqRGlv/hlQCTBBZPLq
 RVUsEiE36UlSuipyruK34KubtVkbqUgUjBiPygFr6cLKb6fc6sjWrK5P8KUtN860
 8q1froUK43gwdVcdmLgrMbFCspE+KUp3xzSDh9tcVq6Ffw+otuuC0cJeVG4j+GOf
 xntsUqlAX6XSudTvTfa1pqvQmynBqvBy4wW9yrRfvEJ6eJqRlT17Sbs6AzpeLE4k
 dpeHlHwHtk5kfEGkYarJ3CEDw1GfHdLfQ6B6lBmCKq6DwnTZbq+lX5C3wB+OXVom
 xn5enCuaygVnXs6RF6DP3KlSvLoCJ09BEehkERxVg1uyVnGkioXXwNU8vdjkj2Qd
 srITNeo=
 =hJ5w
 -----END PGP SIGNATURE-----

Merge tag 'sound-fix-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "A collection of small bug fixes accumulated over the last week.
  Most are device-specific fixes while there are a few core fixes as
  well.

  Here are the highlights:

  ALSA Core:
   - A fix for an uninitialised heap leak in ALSA sequencer core
   - A fix for error handling/resource leak in compress-offload API

  USB-audio:
   - A teardown-ordering fix in USB MIDI 2.0 to prevent use-after-free
   - Bounds and length checks for packet data in Native Instruments
     caiaq / Traktor Kontrol input parsers
   - Avoidance of expensive kobject path lookups in DualSense controller
     matches
   - Robustness/memory leak fixes for Qualcomm USB offload driver
   - Focusrite Control Protocol (FCP) NULL-pointer dereference fix and a
     new device quirk (ISA C8X)
   - Device-specific quirks for Yamaha CDS3000 and SC13A

  HD-Audio:
   - A bunch of quirks and mute/mic-mute LED fixups for various laptops
     (Acer, Clevo, Lenovo, HP)

  ASoC & SoundWire:
   - Avoid failing card registration if the device_link creation fails
   - A workaround for SoundWire randconfig build failures by making
     helper functions static inline
   - Corrected MCLK reference validation for CS530x codecs
   - Clean up of untested, problematic guard() macro replacements in
     Rockchip SAI driver
   - Fix for eDMA maxburst misalignment with channel count in Freescale
     ASRC
   - Miscellaneous hardware-specific fixes (qcom, rt5650, tlv320aic3x,
     tas2781/3)

  Others:
   - Bounds and length checks for packet data in Apple iSight"

* tag 'sound-fix-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (46 commits)
  ALSA: FCP: Fix NULL pointer dereference in interface lookup
  ALSA: hda/realtek: Update Acer Nitro ANV15-41 quirk to enable mute LED
  ASoC: fsl_asrc_dma: fix eDMA maxburst misalignment with channel count
  ASoC: codecs: pcm512x: only print info once on no sclk
  ASoC: tas2781: Update default register address to TAS2563
  ALSA: firewire: isight: bound the sample count to the packet payload
  ALSA: usb-audio: qcom: Free QMI handle
  ALSA: hda: Add Lenovo Legion 7i 16IAX7 17AA3874 quirk
  ALSA: usb-audio: avoid kobject path lookup in DualSense match
  ALSA: hda/realtek: Add quirk for Acer Nitro ANV15-41
  ASoC: soc-core: Don't fail if device_link could not be created
  ASoC: rockchip: rockchip_sai: #include <linux/platform_device.h> explicitly
  ALSA: seq: Fix uninitialised heap leak in snd_seq_event_dup()
  ASoC: rt5575: Use __le32 for SPI burst write address
  ASoC: tas2783: Update loaded firmware names to linux-firmware 20260519
  ASoC: SDCA: Validate written enum value in ge_put_enum_double()
  ASoC: realtek: Add back local call to sdw_show_ping_status()
  ASoC: ti: Add back local call to sdw_show_ping_status()
  ASoC: max98373: Add back local call to sdw_show_ping_status()
  ASoC: es9356: Add back local call to sdw_show_ping_status()
  ...
This commit is contained in:
Linus Torvalds 2026-06-27 12:15:23 -07:00
commit 14923571e7
49 changed files with 481 additions and 316 deletions

View File

@ -1372,34 +1372,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *slave)
}
EXPORT_SYMBOL_GPL(sdw_slave_get_current_bank);
/**
* sdw_slave_wait_for_init - Wait for device initialisation
* @slave: Pointer to the SoundWire peripheral.
* @timeout_ms: Timeout in milliseconds.
*
* Wait for a peripheral device to enumerate and be initialised by the
* SoundWire core.
*
* Return: Zero on success, and a negative error code on failure.
*/
int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
{
unsigned long time;
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(timeout_ms));
if (!time) {
dev_err(&slave->dev, "Initialization not complete\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}
slave->unattach_request = 0;
return 0;
}
EXPORT_SYMBOL_GPL(sdw_slave_wait_for_init);
static int sdw_slave_set_frequency(struct sdw_slave *slave)
{
int scale_index;

View File

@ -11,6 +11,7 @@
#include <linux/idr.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/jiffies.h>
#include <linux/lockdep_types.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
@ -1093,8 +1094,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *sdev);
int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base);
int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms);
/* messaging and data APIs */
int sdw_read(struct sdw_slave *slave, u32 addr);
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
@ -1138,12 +1137,6 @@ static inline int sdw_slave_get_current_bank(struct sdw_slave *sdev)
return -EINVAL;
}
static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
{
WARN_ONCE(1, "SoundWire API is disabled");
return -EINVAL;
}
/* messaging and data APIs */
static inline int sdw_read(struct sdw_slave *slave, u32 addr)
{
@ -1207,4 +1200,33 @@ static inline int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u
#endif /* CONFIG_SOUNDWIRE */
/**
* sdw_slave_wait_for_init - Wait for device initialisation
* @slave: Pointer to the SoundWire peripheral.
* @timeout_ms: Timeout in milliseconds.
*
* Wait for a peripheral device to enumerate and be initialised by the
* SoundWire core.
*
* Return: Zero on success, and a negative error code on failure.
*/
static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
{
unsigned long time;
if (!slave)
return 0;
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(timeout_ms));
if (!time) {
dev_err(&slave->dev, "Initialization not complete\n");
return -ETIMEDOUT;
}
slave->unattach_request = 0;
return 0;
}
#endif /* __SOUNDWIRE_H */

View File

@ -10,6 +10,8 @@
#include <sound/soc.h>
struct device_link;
/*
* Component probe and remove ordering levels for components with runtime
* dependencies.
@ -216,6 +218,8 @@ struct snd_soc_component {
struct list_head card_aux_list; /* for auxiliary bound components */
struct list_head card_list;
struct device_link *card_device_link;
const struct snd_soc_component_driver *driver;
struct list_head dai_list;

View File

@ -59,9 +59,9 @@
#define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e)
/* XM_340 */
#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x63, 0x3c)
#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x02, 0x4c)
/* XM_341 */
#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x63, 0x38)
#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x02, 0x64)
/* Volume control */
#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0c)

View File

@ -1083,15 +1083,18 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_
file descriptors are allocated before fd_install() */
if (!task->input || !task->input->file || !task->output || !task->output->file) {
retval = -EINVAL;
goto cleanup;
goto free_driver_task;
}
fd_i = get_unused_fd_flags(O_WRONLY|O_CLOEXEC);
if (fd_i < 0)
goto cleanup;
if (fd_i < 0) {
retval = fd_i;
goto free_driver_task;
}
fd_o = get_unused_fd_flags(O_RDONLY|O_CLOEXEC);
if (fd_o < 0) {
retval = fd_o;
put_unused_fd(fd_i);
goto cleanup;
goto free_driver_task;
}
/* keep dmabuf reference until freed with task free ioctl */
get_dma_buf(task->input);
@ -1103,6 +1106,8 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_
list_add_tail(&task->list, &stream->runtime->tasks);
stream->runtime->total_tasks++;
return 0;
free_driver_task:
stream->ops->task_free(stream, task);
cleanup:
snd_compr_task_free(task);
return retval;

View File

@ -545,7 +545,7 @@ void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
const unsigned char *id, unsigned int len)
{
*(__u32 *)params->sync = cpu_to_le32(substream->pcm->card->number);
*(__le32 *)params->sync = cpu_to_le32(substream->pcm->card->number);
len = min(12, len);
memcpy(params->sync + 4, id, len);
memset(params->sync + 4 + len, 0, 12 - len);

View File

@ -364,7 +364,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
size = snd_seq_event_packet_size(event);
memcpy(&cell->ump, event, size);
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
if (size < sizeof(cell->event))
if (size < sizeof(cell->ump))
cell->ump.raw.extra = 0;
#endif

View File

@ -179,7 +179,8 @@ static void isight_packet(struct fw_iso_context *context, u32 cycle,
if (likely(length >= 16 &&
payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
count = be32_to_cpu(payload->sample_count);
if (likely(count <= (length - 16) / 4)) {
if (likely(count <= (length - 16) / 4 &&
count <= MAX_FRAMES_PER_PACKET)) {
total = be32_to_cpu(payload->sample_total);
if (unlikely(total != isight->total_samples)) {
if (!isight->first_packet)

View File

@ -291,6 +291,7 @@ enum {
CXT_FIXUP_HEADSET_MIC,
CXT_FIXUP_HP_MIC_NO_PRESENCE,
CXT_PINCFG_SWS_JS201D,
CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10,
CXT_PINCFG_TOP_SPEAKER,
CXT_FIXUP_HP_A_U,
CXT_FIXUP_ACER_SWIFT_HP,
@ -826,6 +827,12 @@ static const struct hda_pintbl cxt_pincfg_lemote[] = {
{}
};
/* Lenovo IdeaPad Slim 5 16AKP10 with SN6140 */
static const struct hda_pintbl cxt_pincfg_lenovo_ideapad_slim5_16akp10[] = {
{ 0x1a, 0x95a60130 }, /* Internal mic, fixed/always-connected */
{}
};
/* SuoWoSi/South-holding JS201D with sn6140 */
static const struct hda_pintbl cxt_pincfg_sws_js201d[] = {
{ 0x16, 0x03211040 }, /* hp out */
@ -1006,6 +1013,10 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_PINS,
.v.pins = cxt_pincfg_sws_js201d,
},
[CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10] = {
.type = HDA_FIXUP_PINS,
.v.pins = cxt_pincfg_lenovo_ideapad_slim5_16akp10,
},
[CXT_PINCFG_TOP_SPEAKER] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@ -1114,6 +1125,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
SND_PCI_QUIRK(0x17aa, 0x38b6, "Lenovo IdeaPad Slim 5 16AKP10", CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10),
SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),

View File

@ -6807,11 +6807,13 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC287_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x161f, "Acer S40-54", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1758, "Acer Nitro ANV15-41", ALC245_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
@ -6986,6 +6988,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8548, "HP EliteBook x360 830 G6", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x854a, "HP EliteBook 830 G6", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x854d, "HP EliteBook 840 G6", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x856a, "HP Pavilion 15-cs1xxx", ALC295_FIXUP_HP_PAVILION_MUTE_LED_1B),
SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11),
SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360),
@ -7326,6 +7329,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f2d, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f2e, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f37, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f38, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f39, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f3a, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f3c, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8f3d, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8f40, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
@ -7597,6 +7604,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x51b3, "Clevo NS70AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x5700, "Clevo X560WN[RST]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x6480, "Clevo V6xxAW", ALC245_FIXUP_CLEVO_NOISY_MIC),
SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@ -7753,11 +7761,13 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x386a, "Lenovo Yoga 7 16IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1),
HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */
SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C),
SND_PCI_QUIRK(0x17aa, 0x3874, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C),

View File

@ -128,6 +128,7 @@ static const struct cs35l41_config cs35l41_config_table[] = {
{ "17AA3866", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA386E", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
{ "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA3874", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA3877", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA3878", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
@ -554,6 +555,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
{ "CSC3551", "17AA3866", generic_dsd_config },
{ "CSC3551", "17AA386E", generic_dsd_config },
{ "CSC3551", "17AA386F", generic_dsd_config },
{ "CSC3551", "17AA3874", generic_dsd_config },
{ "CSC3551", "17AA3877", generic_dsd_config },
{ "CSC3551", "17AA3878", generic_dsd_config },
{ "CSC3551", "17AA38A9", generic_dsd_config },

View File

@ -1181,19 +1181,17 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_playback;
err = snd_emu10k1_playback_set_constraints(runtime);
if (err < 0) {
kfree(epcm);
return err;
}
if (err < 0)
goto free_epcm;
if (emu->card_capabilities->emu_model)
sample_rate = emu->emu1010.word_clock;
else
sample_rate = 48000;
err = snd_pcm_hw_rule_noresample(runtime, sample_rate);
if (err < 0) {
kfree(epcm);
return err;
}
if (err < 0)
goto free_epcm;
mix = &emu->pcm_mixer[substream->number];
for (i = 0; i < 8; i++)
mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i;
@ -1204,6 +1202,10 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
mix->epcm = epcm;
snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1);
return 0;
free_epcm:
kfree(epcm);
return err;
}
static int snd_emu10k1_playback_close(struct snd_pcm_substream *substream)

View File

@ -564,10 +564,9 @@ static int snd_aica_probe(struct platform_device *devptr)
return -ENOMEM;
err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER,
THIS_MODULE, 0, &dreamcastcard->card);
if (unlikely(err < 0)) {
kfree(dreamcastcard);
return err;
}
if (unlikely(err < 0))
goto free_card;
strscpy(dreamcastcard->card->driver, "snd_aica");
strscpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
strscpy(dreamcastcard->card->longname,
@ -593,6 +592,7 @@ static int snd_aica_probe(struct platform_device *devptr)
return 0;
freedreamcast:
snd_card_free(dreamcastcard->card);
free_card:
kfree(dreamcastcard);
return err;
}

View File

@ -1093,6 +1093,29 @@ static int cs530x_component_probe(struct snd_soc_component *component)
return 0;
}
static bool cs530x_mclk_freq_is_valid(struct cs530x_priv *cs530x,
unsigned int freq)
{
/*
* All these chips support 48 kHz- and 44.1 kHz-related sample rates,
* but they differ in what MCLK frequency is required for achieving
* the sample rate.
*/
switch (cs530x->devtype) {
case CS4282:
case CS4302:
case CS4304:
case CS4308:
return freq == 49152000 || freq == 45158400;
case CS5302:
case CS5304:
case CS5308:
return freq == 24576000 || freq == 22579200;
}
return false;
}
static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
int source, unsigned int freq, int dir)
{
@ -1101,11 +1124,7 @@ static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
switch (source) {
case CS530X_SYSCLK_SRC_MCLK:
switch (freq) {
case CS530X_SYSCLK_REF_45_1MHZ:
case CS530X_SYSCLK_REF_49_1MHZ:
break;
default:
if (!cs530x_mclk_freq_is_valid(cs530x, freq)) {
dev_err(component->dev, "Invalid MCLK source rate %d\n", freq);
return -EINVAL;
}

View File

@ -200,12 +200,6 @@
/* IN_VOL_CTL5 and OUT_VOL_CTL5 */
#define CS530X_INOUT_VU BIT(0)
/* MCLK Reference Source Frequency */
/* 41KHz related */
#define CS530X_SYSCLK_REF_45_1MHZ 45158400
/* 48KHz related */
#define CS530X_SYSCLK_REF_49_1MHZ 49152000
/* System Clock Source */
#define CS530X_SYSCLK_SRC_MCLK 0
#define CS530X_SYSCLK_SRC_PLL 1

View File

@ -1111,8 +1111,10 @@ static int es9356_sdca_dev_resume(struct device *dev)
es9356->disable_irq = false;
ret = sdw_slave_wait_for_init(slave, es9356_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(es9356->regmap, false);
regcache_sync(es9356->regmap);

View File

@ -272,8 +272,10 @@ static int max98373_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, MAX98373_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(max98373->regmap, false);
regcache_sync(max98373->regmap);

View File

@ -633,7 +633,7 @@ static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
struct regmap *regmap = pcm512x->regmap;
if (IS_ERR(pcm512x->sclk)) {
dev_info(dev, "No SCLK, using BCLK: %ld\n",
dev_info_once(dev, "No SCLK, using BCLK: %ld\n",
PTR_ERR(pcm512x->sclk));
/* Disable reporting of missing SCLK as an error */

View File

@ -779,8 +779,10 @@ static int rt1017_sdca_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT1017_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt1017->regmap, false);
regcache_sync(rt1017->regmap);

View File

@ -774,8 +774,10 @@ static int rt1308_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT1308_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt1308->regmap, false);
regcache_sync_region(rt1308->regmap, 0xc000, 0xcfff);

View File

@ -751,8 +751,10 @@ static int rt1316_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT1316_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt1316->regmap, false);
regcache_sync(rt1316->regmap);

View File

@ -17,7 +17,7 @@
struct rt5575_spi_burst_write {
u8 cmd;
u32 addr;
__le32 addr;
u8 data[RT5575_SPI_BUF_LEN];
u8 dummy;
} __packed;

View File

@ -83,6 +83,8 @@ static const struct reg_sequence rt5650_init_list[] = {
{RT5645_PWR_ANLG1, 0x02},
{RT5645_IL_CMD3, 0x6728},
{RT5645_PR_BASE + 0x3a, 0x0000},
{RT5645_CLSD_OUT_CTRL1, 0x4059},
{RT5645_GEN_CTRL3, 0x0200},
};
static const struct reg_default rt5645_reg[] = {
@ -1855,13 +1857,9 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
RT5645_PWR_CLS_D_L,
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
RT5645_PWR_CLS_D_L);
snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
snd_soc_component_write(component, RT5645_EQ_CTRL2, 0);
snd_soc_component_update_bits(component, RT5645_PWR_DIG1,
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |

View File

@ -118,6 +118,7 @@
#define RT5645_A_JD_CTRL1 0x94
#define RT5645_VAD_CTRL4 0x9d
#define RT5645_CLSD_OUT_CTRL 0xa0
#define RT5645_CLSD_OUT_CTRL1 0xa1
/* Function - Digital */
#define RT5645_ADC_EQ_CTRL1 0xae
#define RT5645_ADC_EQ_CTRL2 0xaf

View File

@ -769,8 +769,10 @@ static int rt5682_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt5682->sdw_regmap, false);
regcache_cache_only(rt5682->regmap, false);

View File

@ -528,8 +528,10 @@ static int rt700_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT700_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt700->regmap, false);
regcache_sync_region(rt700->regmap, 0x3000, 0x8fff);

View File

@ -454,8 +454,10 @@ static int rt711_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt711->regmap, false);
regcache_sync(rt711->regmap);

View File

@ -911,8 +911,10 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt712->regmap, false);
regcache_sync(rt712->regmap);

View File

@ -467,8 +467,10 @@ static int rt712_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt712->regmap, false);
regcache_sync(rt712->regmap);

View File

@ -230,8 +230,10 @@ static int rt715_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt715->regmap, false);
regcache_sync_region(rt715->regmap,

View File

@ -507,8 +507,10 @@ static int rt715_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt715->regmap, false);
regcache_sync_region(rt715->regmap, 0x3000, 0x8fff);

View File

@ -505,8 +505,10 @@ static int rt721_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt721->regmap, false);
regcache_sync(rt721->regmap);

View File

@ -552,8 +552,10 @@ static int rt722_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(rt722->regmap, false);
regcache_sync(rt722->regmap);

View File

@ -1445,8 +1445,10 @@ static s32 tac5xx2_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, TAC5XX2_PROBE_TIMEOUT_MS);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(tac_dev->regmap, false);
regcache_mark_dirty(tac_dev->regmap);

View File

@ -100,6 +100,8 @@ struct tas2783_prv {
wait_queue_head_t fw_wait;
bool fw_dl_task_done;
bool fw_dl_success;
/* use fallback fw name */
bool fw_use_fallback;
};
static const struct reg_default tas2783_reg_default[] = {
@ -740,11 +742,19 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
goto out;
}
/* firmware binary not found*/
if (!fmw || !fmw->data) {
/* firmware binary not found*/
dev_err(tas_dev->dev,
"Failed to read fw binary %s\n",
tas_dev->rca_binaryname);
if (!tas_dev->fw_use_fallback) {
tas_dev->fw_use_fallback = true;
dev_info(tas_dev->dev,
"Failed to read preferred fw binary: %s, attempting fallback binary load\n",
tas_dev->rca_binaryname);
} else {
dev_err(tas_dev->dev,
"Failed to read fallback fw binary %s\n",
tas_dev->rca_binaryname);
}
ret = -EINVAL;
goto out;
}
@ -1083,8 +1093,10 @@ static s32 tas2783_sdca_dev_resume(struct device *dev)
int ret;
ret = sdw_slave_wait_for_init(slave, TAS2783_PROBE_TIMEOUT);
if (ret)
if (ret) {
sdw_show_ping_status(slave->bus, true);
return ret;
}
regcache_cache_only(tas_dev->regmap, false);
regcache_sync(tas_dev->regmap);
@ -1103,13 +1115,16 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
bool pci_found = false;
#if IS_ENABLED(CONFIG_PCI)
struct device *dev = &slave->dev;
struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev);
struct pci_dev *pci = NULL;
const char *fw_uid_prefix = tas_dev->fw_use_fallback ? "" : "0x";
for (; dev; dev = dev->parent) {
if (dev->bus == &pci_bus_type) {
pci = to_pci_dev(dev);
scnprintf(name, size, "%04X-%1X-%1X.bin",
pci->subsystem_device, bus->link_id, unique_id);
scnprintf(name, size, "%04X-%1X-%s%1X.bin",
pci->subsystem_device, bus->link_id,
fw_uid_prefix, unique_id);
pci_found = true;
break;
}
@ -1121,28 +1136,15 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
bus->link_id, unique_id);
}
static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
{
struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
s32 ret;
u8 unique_id = tas_dev->sdw_peripheral->id.unique_id;
if (tas_dev->hw_init)
return 0;
tas_dev->fw_dl_task_done = false;
tas_dev->fw_dl_success = false;
ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
if (ret) {
dev_err(dev, "sw reset failed, err=%d", ret);
return ret;
}
usleep_range(2000, 2200);
tas_generate_fw_name(slave, tas_dev->rca_binaryname,
sizeof(tas_dev->rca_binaryname));
tas_dev->fw_dl_task_done = false;
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
tas_dev->rca_binaryname, tas_dev->dev,
GFP_KERNEL, tas_dev, tas2783_fw_ready);
@ -1157,8 +1159,35 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
msecs_to_jiffies(TIMEOUT_FW_DL_MS));
if (!ret) {
dev_err(tas_dev->dev, "fw request, wait_event timeout\n");
ret = -EAGAIN;
} else {
return -EAGAIN;
}
return 0;
}
static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
{
struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
s32 ret;
if (tas_dev->hw_init)
return 0;
tas_dev->fw_dl_success = false;
ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
if (ret) {
dev_err(dev, "sw reset failed, err=%d", ret);
return ret;
}
usleep_range(2000, 2200);
tas_dev->fw_use_fallback = false;
ret = tas_fw_load(tas_dev, slave);
if (!ret && tas_dev->fw_use_fallback)
ret = tas_fw_load(tas_dev, slave);
if (!ret) {
if (tas_dev->sa_func_data)
ret = sdca_regmap_write_init(dev, tas_dev->regmap,
tas_dev->sa_func_data);

View File

@ -1049,11 +1049,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
static const u8 dual_rate_q[] = {4, 8, 9, 12, 16};
struct snd_soc_component *component = dai->component;
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
u16 d, pll_d = 1;
bool dual_rate;
int clk;
int width = aic3x->slot_width;
@ -1079,14 +1081,25 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
/* Fsref can be 44100 or 48000 */
fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
dual_rate = params_rate(params) >= 64000;
/* Try to find a value for Q which allows us to bypass the PLL and
* generate CODEC_CLK directly. */
for (pll_q = 2; pll_q < 18; pll_q++)
if (aic3x->sysclk / (128 * pll_q) == fsref) {
bypass_pll = 1;
break;
if (dual_rate) {
for (int i = 0; i < ARRAY_SIZE(dual_rate_q); i++) {
pll_q = dual_rate_q[i];
if (aic3x->sysclk / (128 * pll_q) == fsref) {
bypass_pll = 1;
break;
}
}
} else {
for (pll_q = 2; pll_q < 18; pll_q++)
if (aic3x->sysclk / (128 * pll_q) == fsref) {
bypass_pll = 1;
break;
}
}
if (bypass_pll) {
pll_q &= 0xf;
@ -1106,13 +1119,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
* right DAC to right channel input */
data = (LDAC2LCH | RDAC2RCH);
data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
if (params_rate(params) >= 64000)
if (dual_rate)
data |= DUAL_RATE_MODE;
snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data);
/* codec sample rate select */
data = (fsref * 20) / params_rate(params);
if (params_rate(params) < 64000)
if (!dual_rate)
data /= 2;
data /= 5;
data -= 2;

View File

@ -288,6 +288,26 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
config_be.dst_addr_width = buswidth;
config_be.dst_maxburst = dma_params_be->maxburst;
/*
* For eDMA, the back-end may report a maxburst size that is not evenly
* divisible by the channel count. This causes the DMA transfer length
* to misalign with the FIFO boundary, resulting in wrong data and
* audible noise. Align maxburst to the nearest valid boundary:
* - If maxburst >= channel count, override to the channel count so
* each transfer equals exactly one audio frame.
* - If maxburst < channel count, override to 1 to avoid partial-frame
* transfers.
*/
if (asrc->use_edma && (dma_params_be->maxburst % params_channels(params))) {
if (dma_params_be->maxburst >= params_channels(params)) {
config_be.src_maxburst = params_channels(params);
config_be.dst_maxburst = params_channels(params);
} else {
config_be.src_maxburst = 1;
config_be.dst_maxburst = 1;
}
}
memset(&audio_config, 0, sizeof(audio_config));
config_be.peripheral_config = &audio_config;
config_be.peripheral_size = sizeof(audio_config);

View File

@ -778,18 +778,6 @@ static void graph_link_init(struct simple_util_priv *priv,
graph_parse_daifmt(ports_cpu, &daifmt);
graph_parse_daifmt(ports_codec, &daifmt);
graph_parse_daifmt(lnk, &daifmt);
if (daifmt) {
struct device *dev = simple_priv_to_dev(priv);
/*
* Recommend to use Auto Select by using .auto_selectable_formats.
* linux/sound/soc/renesas/rcar/core.c can be good sample for it.
*
* One note is that Audio Graph Card2 still keeps compatible to set
* DAI format via DT.
*/
dev_warn_once(dev, "use .auto_selectable_formats on each corresponding CPU/Codec driver");
}
graph_util_parse_link_direction(lnk, &playback_only, &capture_only);
graph_util_parse_link_direction(ports_cpu, &playback_only, &capture_only);

View File

@ -587,6 +587,10 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
token = hdr->token & APM_WRITE_TOKEN_MASK;
done = data->payload;
if (!graph->rx_data.buf) {
mutex_unlock(&graph->lock);
break;
}
phys = graph->rx_data.buf[token].phys;
mutex_unlock(&graph->lock);
/* token numbering starts at 0 */
@ -609,6 +613,10 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
mutex_lock(&graph->lock);
rd_done = data->payload;
if (!graph->tx_data.buf) {
mutex_unlock(&graph->lock);
break;
}
phys = graph->tx_data.buf[hdr->token].phys;
mutex_unlock(&graph->lock);
/* token numbering starts at 0 */

View File

@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@ -18,6 +19,7 @@
#include <sound/pcm_params.h>
#include <sound/dmaengine_pcm.h>
#include <sound/tlv.h>
#include "rockchip_sai.h"
#define DRV_NAME "rockchip-sai"
@ -215,12 +217,14 @@ static void rockchip_sai_xfer_clk_stop_and_wait(struct rk_sai_dev *sai, unsigned
static int rockchip_sai_runtime_suspend(struct device *dev)
{
struct rk_sai_dev *sai = dev_get_drvdata(dev);
unsigned long flags;
rockchip_sai_fsync_lost_detect(sai, 0);
rockchip_sai_fsync_err_detect(sai, 0);
scoped_guard(spinlock_irqsave, &sai->xfer_lock)
rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
spin_lock_irqsave(&sai->xfer_lock, flags);
rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
spin_unlock_irqrestore(&sai->xfer_lock, flags);
regcache_cache_only(sai->regmap, true);
/*
@ -480,6 +484,7 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
unsigned int mask = 0, val = 0;
unsigned int clk_gates;
unsigned long flags;
int ret = 0;
pm_runtime_get_sync(dai->dev);
@ -495,56 +500,56 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
sai->is_master_mode = false;
break;
default:
pm_runtime_put(dai->dev);
return -EINVAL;
ret = -EINVAL;
goto err_pm_put;
}
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
if (sai->initialized) {
if (sai->has_capture && sai->has_playback)
rockchip_sai_xfer_stop(sai, -1);
else if (sai->has_capture)
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
else
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
} else {
rockchip_sai_clear(sai, 0);
sai->initialized = true;
}
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
break;
case SND_SOC_DAIFMT_NB_IF:
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
break;
case SND_SOC_DAIFMT_IB_NF:
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
break;
case SND_SOC_DAIFMT_IB_IF:
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
break;
default:
ret = -EINVAL;
break;
}
if (ret == 0) {
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
rockchip_sai_fmt_create(sai, fmt);
}
if (clk_gates)
regmap_update_bits(sai->regmap, SAI_XFER,
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
clk_gates);
spin_lock_irqsave(&sai->xfer_lock, flags);
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
if (sai->initialized) {
if (sai->has_capture && sai->has_playback)
rockchip_sai_xfer_stop(sai, -1);
else if (sai->has_capture)
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
else
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
} else {
rockchip_sai_clear(sai, 0);
sai->initialized = true;
}
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
break;
case SND_SOC_DAIFMT_NB_IF:
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
break;
case SND_SOC_DAIFMT_IB_NF:
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
break;
case SND_SOC_DAIFMT_IB_IF:
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
break;
default:
ret = -EINVAL;
goto err_xfer_unlock;
}
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
rockchip_sai_fmt_create(sai, fmt);
err_xfer_unlock:
if (clk_gates)
regmap_update_bits(sai->regmap, SAI_XFER,
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
clk_gates);
spin_unlock_irqrestore(&sai->xfer_lock, flags);
err_pm_put:
pm_runtime_put(dai->dev);
return ret;
@ -560,6 +565,7 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
unsigned int ch_per_lane, slot_width;
unsigned int val, fscr, reg;
unsigned int lanes, req_lanes;
unsigned long flags;
int ret = 0;
if (!rockchip_sai_stream_valid(substream, dai))
@ -586,8 +592,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
dev_err(sai->dev, "not enough lanes (%d) for requested number of %s channels (%d)\n",
lanes, reg == SAI_TXCR ? "playback" : "capture",
params_channels(params));
pm_runtime_put(sai->dev);
return -EINVAL;
ret = -EINVAL;
goto err_pm_put;
} else {
lanes = req_lanes;
}
@ -613,88 +619,84 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
val = SAI_XCR_VDW(32);
break;
default:
pm_runtime_put(sai->dev);
return -EINVAL;
ret = -EINVAL;
goto err_pm_put;
}
val |= SAI_XCR_CSR(lanes);
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
spin_lock_irqsave(&sai->xfer_lock, flags);
regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
if (!sai->is_tdm)
regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
SAI_XCR_SBW(params_physical_width(params)));
if (!sai->is_tdm)
regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
SAI_XCR_SBW(params_physical_width(params)));
regmap_read(sai->regmap, reg, &val);
regmap_read(sai->regmap, reg, &val);
slot_width = SAI_XCR_SBW_V(val);
ch_per_lane = params_channels(params) / lanes;
slot_width = SAI_XCR_SBW_V(val);
ch_per_lane = params_channels(params) / lanes;
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
SAI_XCR_SNB(ch_per_lane));
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
SAI_XCR_SNB(ch_per_lane));
fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
switch (sai->fpw) {
case FPW_ONE_BCLK_WIDTH:
fscr |= SAI_FSCR_FPW(1);
break;
case FPW_ONE_SLOT_WIDTH:
fscr |= SAI_FSCR_FPW(slot_width);
break;
case FPW_HALF_FRAME_WIDTH:
fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
break;
default:
dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
ret = -EINVAL;
break;
}
if (ret == 0) {
regmap_update_bits(sai->regmap, SAI_FSCR,
SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
if (sai->is_master_mode) {
bclk_rate = sai->fw_ratio * slot_width *
ch_per_lane * params_rate(params);
ret = clk_set_rate(sai->mclk, sai->mclk_rate);
if (ret)
dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
sai->mclk_rate, ERR_PTR(ret));
else {
mclk_rate = clk_get_rate(sai->mclk);
if (mclk_rate < bclk_rate) {
dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
mclk_rate, bclk_rate);
ret = -EINVAL;
} else {
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
mclk_req_rate = bclk_rate * div_bclk;
if (mclk_rate <
mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
mclk_rate >
mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
dev_err(sai->dev,
"Mismatch mclk: %u, expected %u (+/- %dHz)\n",
mclk_rate, mclk_req_rate,
CLK_SHIFT_RATE_HZ_MAX);
ret = -EINVAL;
} else
regmap_update_bits(sai->regmap,
SAI_CKR,
SAI_CKR_MDIV_MASK,
SAI_CKR_MDIV(div_bclk));
}
}
}
}
switch (sai->fpw) {
case FPW_ONE_BCLK_WIDTH:
fscr |= SAI_FSCR_FPW(1);
break;
case FPW_ONE_SLOT_WIDTH:
fscr |= SAI_FSCR_FPW(slot_width);
break;
case FPW_HALF_FRAME_WIDTH:
fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
break;
default:
dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
ret = -EINVAL;
goto err_xfer_unlock;
}
regmap_update_bits(sai->regmap, SAI_FSCR,
SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
if (sai->is_master_mode) {
bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params);
ret = clk_set_rate(sai->mclk, sai->mclk_rate);
if (ret) {
dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
sai->mclk_rate, ERR_PTR(ret));
goto err_xfer_unlock;
}
mclk_rate = clk_get_rate(sai->mclk);
if (mclk_rate < bclk_rate) {
dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
mclk_rate, bclk_rate);
ret = -EINVAL;
goto err_xfer_unlock;
}
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
mclk_req_rate = bclk_rate * div_bclk;
if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX);
ret = -EINVAL;
goto err_xfer_unlock;
}
regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
SAI_CKR_MDIV(div_bclk));
}
err_xfer_unlock:
spin_unlock_irqrestore(&sai->xfer_lock, flags);
err_pm_put:
pm_runtime_put(sai->dev);
return ret;
@ -704,6 +706,7 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
unsigned long flags;
if (!rockchip_sai_stream_valid(substream, dai))
return 0;
@ -724,12 +727,13 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
* udelay falls short.
*/
udelay(20);
scoped_guard(spinlock_irqsave, &sai->xfer_lock)
regmap_update_bits(sai->regmap, SAI_XFER,
SAI_XFER_CLK_MASK |
SAI_XFER_FSS_MASK,
SAI_XFER_CLK_EN |
SAI_XFER_FSS_EN);
spin_lock_irqsave(&sai->xfer_lock, flags);
regmap_update_bits(sai->regmap, SAI_XFER,
SAI_XFER_CLK_MASK |
SAI_XFER_FSS_MASK,
SAI_XFER_CLK_EN |
SAI_XFER_FSS_EN);
spin_unlock_irqrestore(&sai->xfer_lock, flags);
}
rockchip_sai_fsync_lost_detect(sai, 1);
@ -912,6 +916,7 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
int slots, int slot_width)
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
unsigned long flags;
unsigned int clk_gates;
int sw = slot_width;
@ -927,16 +932,16 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
pm_runtime_get_sync(dai->dev);
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
SAI_XCR_SBW(sw));
regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
SAI_XCR_SBW(sw));
regmap_update_bits(sai->regmap, SAI_XFER,
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
clk_gates);
}
spin_lock_irqsave(&sai->xfer_lock, flags);
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
SAI_XCR_SBW(sw));
regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
SAI_XCR_SBW(sw));
regmap_update_bits(sai->regmap, SAI_XFER,
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
clk_gates);
spin_unlock_irqrestore(&sai->xfer_lock, flags);
pm_runtime_put(dai->dev);
return 0;

View File

@ -160,6 +160,9 @@ static int ge_put_enum_double(struct snd_kcontrol *kcontrol,
unsigned int reg = e->reg;
int ret;
if (item[0] >= e->items)
return -EINVAL;
reg &= ~SDW_SDCA_CTL_CSEL(0x3F);
reg |= SDW_SDCA_CTL_CSEL(SDCA_CTL_GE_DETECTED_MODE);

View File

@ -1980,19 +1980,15 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
}
}
static void snd_soc_remove_device_links(struct snd_soc_card *card,
struct snd_soc_component *stop_at)
static void snd_soc_remove_device_links(struct snd_soc_card *card)
{
struct snd_soc_component *component;
for_each_card_components(card, component) {
if (card->dev == component->dev)
continue;
device_link_remove(card->dev, component->dev);
if (component == stop_at)
return;
if (component->card_device_link) {
device_link_del(component->card_device_link);
component->card_device_link = NULL;
}
}
}
@ -2001,7 +1997,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card)
if (snd_soc_card_is_instantiated(card)) {
card->instantiated = false;
snd_soc_remove_device_links(card, NULL);
snd_soc_remove_device_links(card);
soc_cleanup_card_resources(card);
}
@ -2012,7 +2008,6 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_component *component;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct snd_soc_component *last_devlinked_component = NULL;
int ret;
snd_soc_card_mutex_lock_root(card);
@ -2141,19 +2136,21 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
* Add device_link from card to component so that system_suspend
* will be done in the correct order. The card must suspend first
* to stop audio activity before the components suspend.
*
* If a driver pair already have a link in the opposite direction
* they must manage their own suspend order.
*/
for_each_card_components(card, component) {
if (card->dev == component->dev)
continue;
if (!device_link_add(card->dev, component->dev, DL_FLAG_STATELESS)) {
dev_warn(card->dev, "Failed to create device link to %s\n",
component->card_device_link = device_link_add(card->dev,
component->dev,
DL_FLAG_STATELESS);
if (!component->card_device_link) {
dev_warn(card->dev, "Could not create device link to %s\n",
dev_name(component->dev));
ret = -EINVAL;
goto probe_end;
}
last_devlinked_component = component;
}
ret = snd_soc_card_late_probe(card);
@ -2185,9 +2182,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
probe_end:
if (ret < 0) {
if (last_devlinked_component)
snd_soc_remove_device_links(card, last_devlinked_component);
snd_soc_remove_device_links(card);
soc_cleanup_card_resources(card);
}

View File

@ -237,12 +237,16 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
if (len < 2)
return;
i = decode_erp(buf[0], buf[1]);
input_report_abs(input_dev, ABS_X, i);
input_sync(input_dev);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
if (len < 16)
return;
i = decode_erp(buf[7], buf[5]);
input_report_abs(input_dev, ABS_HAT0X, i);
i = decode_erp(buf[12], buf[14]);
@ -263,6 +267,8 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
if (len < 22)
return;
/* 4 under the left screen */
input_report_abs(input_dev, ABS_HAT0X, decode_erp(buf[21], buf[20]));
input_report_abs(input_dev, ABS_HAT0Y, decode_erp(buf[15], buf[14]));
@ -308,9 +314,13 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *cdev,
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
if (len < 5)
return;
input_report_abs(cdev->input_dev, ABS_MISC, 255 - buf[4]);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
if (len < 7)
return;
/* rotary encoders */
input_report_abs(cdev->input_dev, ABS_X, buf[5] & 0xf);
input_report_abs(cdev->input_dev, ABS_Y, buf[5] >> 4);
@ -330,7 +340,7 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *cdev,
{
struct device *dev = caiaqdev_to_dev(cdev);
while (len) {
while (len >= TKS4_MSGBLOCK_SIZE) {
unsigned int i, block_id = (buf[0] << 8) | buf[1];
switch (block_id) {

View File

@ -1083,6 +1083,8 @@ static int fcp_find_fc_interface(struct usb_mixer_interface *mixer)
if (desc->bInterfaceClass != 255)
continue;
if (desc->bNumEndpoints < 1)
continue;
epd = get_endpoint(intf->altsetting, 0);
private->bInterfaceNumber = desc->bInterfaceNumber;

View File

@ -470,6 +470,11 @@ static int create_midi2_endpoint(struct snd_usb_midi2_interface *umidi,
static void free_midi2_endpoint(struct snd_usb_midi2_endpoint *ep)
{
list_del(&ep->list);
if (!ep->disconnected) {
ep->disconnected = 1;
kill_midi_urbs(ep, false);
drain_urb_queue(ep);
}
free_midi_urbs(ep);
kfree(ep);
}

View File

@ -577,46 +577,30 @@ static bool snd_dualsense_ih_match(struct input_handler *handler,
{
struct dualsense_mixer_elem_info *mei;
struct usb_device *snd_dev;
char *input_dev_path, *usb_dev_path;
size_t usb_dev_path_len;
bool match = false;
struct device *parent;
mei = container_of(handler, struct dualsense_mixer_elem_info, ih);
snd_dev = mei->info.head.mixer->chip->dev;
input_dev_path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
if (!input_dev_path) {
dev_warn(&snd_dev->dev, "Failed to get input dev path\n");
return false;
}
usb_dev_path = kobject_get_path(&snd_dev->dev.kobj, GFP_KERNEL);
if (!usb_dev_path) {
dev_warn(&snd_dev->dev, "Failed to get USB dev path\n");
goto free_paths;
}
/*
* Ensure the VID:PID matched input device supposedly owned by the
* hid-playstation driver belongs to the actual hardware handled by
* the current USB audio device, which implies input_dev_path being
* a subpath of usb_dev_path.
* the current USB audio device.
*
* This verification is necessary when there is more than one identical
* controller attached to the host system.
*
* The input device is registered below the HID device, USB interface and
* USB device, so compare the parent chain directly instead of building
* kobject path strings. This avoids dereferencing kobject names while the
* USB device hierarchy is being torn down during disconnect.
*/
usb_dev_path_len = strlen(usb_dev_path);
if (usb_dev_path_len >= strlen(input_dev_path))
goto free_paths;
for (parent = dev->dev.parent; parent; parent = parent->parent) {
if (parent == &snd_dev->dev)
return true;
}
usb_dev_path[usb_dev_path_len] = '/';
match = !memcmp(input_dev_path, usb_dev_path, usb_dev_path_len + 1);
free_paths:
kfree(input_dev_path);
kfree(usb_dev_path);
return match;
return false;
}
static int snd_dualsense_ih_connect(struct input_handler *handler,
@ -4526,6 +4510,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x1235, 0x821b): /* Focusrite Scarlett 16i16 4th Gen */
case USB_ID(0x1235, 0x821c): /* Focusrite Scarlett 18i16 4th Gen */
case USB_ID(0x1235, 0x821d): /* Focusrite Scarlett 18i20 4th Gen */
case USB_ID(0x1235, 0x821e): /* Focusrite ISA C8X */
err = snd_fcp_init(mixer);
break;

View File

@ -1160,6 +1160,7 @@ uaudio_endpoint_setup(struct snd_usb_substream *subs,
tr_pa = page_to_phys(pg);
mem_info->dma = sg_dma_address(sgt->sgl);
sg_free_table(sgt);
kfree(sgt);
/* data transfer ring */
iova = uaudio_iommu_map_pa(MEM_XFER_RING, dma_coherent, tr_pa,
@ -1229,6 +1230,7 @@ static int uaudio_event_ring_setup(struct snd_usb_substream *subs,
er_pa = page_to_phys(pg);
mem_info->dma = sg_dma_address(sgt->sgl);
sg_free_table(sgt);
kfree(sgt);
iova = uaudio_iommu_map_pa(MEM_EVENT_RING, dma_coherent, er_pa,
PAGE_SIZE);
@ -1618,8 +1620,13 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle,
if (req_msg->service_interval_valid) {
ret = get_data_interval_from_si(subs,
req_msg->service_interval);
if (ret == -EINVAL)
if (ret == -EINVAL) {
if (req_msg->enable) {
guard(mutex)(&chip->mutex);
subs->opened = 0;
}
goto response;
}
datainterval = ret;
}
@ -1640,6 +1647,11 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle,
subs->opened = 0;
}
} else {
if (info_idx < 0) {
ret = -EINVAL;
goto response;
}
info = &uadev[pcm_card_num].info[info_idx];
if (info->data_ep_pipe) {
ep = usb_pipe_endpoint(uadev[pcm_card_num].udev,
@ -1976,6 +1988,7 @@ static int qc_usb_audio_probe(struct auxiliary_device *auxdev,
release_qmi:
qc_usb_audio_cleanup_qmi_dev();
qmi_handle_release(svc->uaudio_svc_hdl);
kfree(svc->uaudio_svc_hdl);
free_svc:
kfree(svc);
@ -2000,6 +2013,7 @@ static void qc_usb_audio_remove(struct auxiliary_device *auxdev)
qc_usb_audio_cleanup_qmi_dev();
qmi_handle_release(svc->uaudio_svc_hdl);
kfree(svc->uaudio_svc_hdl);
kfree(svc);
uaudio_svc = NULL;
}

View File

@ -390,6 +390,20 @@ YAMAHA_DEVICE(0x105d, NULL),
}
}
},
{
USB_DEVICE(0x0499, 0x150d),
QUIRK_DRIVER_INFO {
/* .vendor_name = "Yamaha", */
/* .product_name = "CDS3000", */
QUIRK_DATA_COMPOSITE {
{ QUIRK_DATA_STANDARD_AUDIO(1) },
{ QUIRK_DATA_STANDARD_AUDIO(2) },
{ QUIRK_DATA_MIDI_YAMAHA(3) },
{ QUIRK_DATA_IGNORE(4) },
QUIRK_COMPOSITE_END
}
}
},
{
USB_DEVICE(0x0499, 0x1718),
QUIRK_DRIVER_INFO {

View File

@ -2413,6 +2413,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
DEVICE_FLG(0x1ff7, 0x0f81, /* SC13A Webcam */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */