diff options
author | Takashi Iwai | 2022-03-21 16:18:26 +0100 |
---|---|---|
committer | Takashi Iwai | 2022-03-21 16:18:34 +0100 |
commit | a6d4b685026cfe9837b07532db5d1e1681b5d129 (patch) | |
tree | da872c8775a1ac87dc8122b1e1f9af19179dcb38 /sound | |
parent | efb6402c3c4a7c26d97c92d70186424097b6e366 (diff) | |
parent | 8a580a26760cb14535c160613fe9cd0e4dc6f5c6 (diff) |
Merge branch 'for-next' into for-linus
Pull 5.18 development branch
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/Kconfig | 2 | ||||
-rw-r--r-- | sound/core/oss/pcm_oss.c | 28 | ||||
-rw-r--r-- | sound/core/seq/oss/seq_oss_init.c | 5 | ||||
-rw-r--r-- | sound/hda/ext/hdac_ext_controller.c | 31 | ||||
-rw-r--r-- | sound/hda/hdac_i915.c | 4 | ||||
-rw-r--r-- | sound/mips/snd-n64.c | 9 | ||||
-rw-r--r-- | sound/pci/ca0106/ca0106.h | 18 | ||||
-rw-r--r-- | sound/pci/ca0106/ca0106_main.c | 70 | ||||
-rw-r--r-- | sound/pci/ca0106/ca0106_mixer.c | 16 | ||||
-rw-r--r-- | sound/pci/echoaudio/midi.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/Kconfig | 19 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 94 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 23 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_tegra.c | 33 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 275 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 47 | ||||
-rw-r--r-- | sound/pci/lola/lola_mixer.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/hdac_hda.c | 2 | ||||
-rw-r--r-- | sound/sound_core.c | 30 | ||||
-rw-r--r-- | sound/spi/at73c213.c | 27 | ||||
-rw-r--r-- | sound/usb/mixer_s1810c.c | 2 | ||||
-rw-r--r-- | sound/usb/mixer_scarlett_gen2.c | 177 | ||||
-rw-r--r-- | sound/x86/intel_hdmi_audio.c | 13 |
24 files changed, 667 insertions, 264 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index db2e3c63ff41..dd7b40734723 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -84,7 +84,7 @@ config SND_PCM_TIMER help If you disable this option, pcm timer will be unavailable, so those stubs that use pcm timer (e.g. dmix, dsnoop & co) may work - incorrectlly. + incorrectly. For some embedded devices, we may disable it to reduce memory footprint, about 20KB on x86_64 platform. diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index f158f0abd25d..90c3a367d7de 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -842,6 +842,17 @@ static void unlock_params(struct snd_pcm_runtime *runtime) mutex_unlock(&runtime->oss.params_lock); } +static void snd_pcm_oss_release_buffers(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + kvfree(runtime->oss.buffer); + runtime->oss.buffer = NULL; +#ifdef CONFIG_SND_PCM_OSS_PLUGINS + snd_pcm_oss_plugin_clear(substream); +#endif +} + /* call with params_lock held */ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) { @@ -972,12 +983,10 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) snd_pcm_oss_plugin_clear(substream); if (!direct) { /* add necessary plugins */ - snd_pcm_oss_plugin_clear(substream); err = snd_pcm_plug_format_plugins(substream, params, sparams); if (err < 0) { pcm_dbg(substream->pcm, "snd_pcm_plug_format_plugins failed: %i\n", err); - snd_pcm_oss_plugin_clear(substream); goto failure; } if (runtime->oss.plugin_first) { @@ -986,7 +995,6 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) if (err < 0) { pcm_dbg(substream->pcm, "snd_pcm_plugin_build_io failed: %i\n", err); - snd_pcm_oss_plugin_clear(substream); goto failure; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -994,10 +1002,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) } else { err = snd_pcm_plugin_insert(plugin); } - if (err < 0) { - snd_pcm_oss_plugin_clear(substream); + if (err < 0) goto failure; - } } } #endif @@ -1086,6 +1092,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) err = 0; failure: + if (err) + snd_pcm_oss_release_buffers(substream); kfree(sw_params); kfree(params); kfree(sparams); @@ -2355,13 +2363,7 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream, static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime; - runtime = substream->runtime; - kvfree(runtime->oss.buffer); - runtime->oss.buffer = NULL; -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - snd_pcm_oss_plugin_clear(substream); -#endif + snd_pcm_oss_release_buffers(substream); substream->oss.oss = 0; } diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 0ee4a5081fd6..42d4e7535a82 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -66,7 +66,7 @@ snd_seq_oss_create_client(void) struct snd_seq_port_info *port; struct snd_seq_port_callback port_callback; - port = kmalloc(sizeof(*port), GFP_KERNEL); + port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) { rc = -ENOMEM; goto __error; @@ -80,8 +80,7 @@ snd_seq_oss_create_client(void) system_client = rc; - /* create annoucement receiver port */ - memset(port, 0, sizeof(*port)); + /* create announcement receiver port */ strcpy(port->name, "Receiver"); port->addr.client = system_client; port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */ diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index b2df7b4f9227..b072392725c7 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -133,6 +133,26 @@ void snd_hdac_link_free_all(struct hdac_bus *bus) EXPORT_SYMBOL_GPL(snd_hdac_link_free_all); /** + * snd_hdac_ext_bus_link_at - get link at specified address + * @bus: link's parent bus device + * @addr: codec device address + * + * Returns link object or NULL if matching link is not found. + */ +struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr) +{ + struct hdac_ext_link *hlink; + int i; + + list_for_each_entry(hlink, &bus->hlink_list, list) + for (i = 0; i < HDA_MAX_CODECS; i++) + if (hlink->lsdiid & (0x1 << addr)) + return hlink; + return NULL; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_at); + +/** * snd_hdac_ext_bus_get_link - get link based on codec name * @bus: the pointer to HDAC bus object * @codec_name: codec name @@ -140,8 +160,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_link_free_all); struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus, const char *codec_name) { - int i; - struct hdac_ext_link *hlink = NULL; int bus_idx, addr; if (sscanf(codec_name, "ehdaudio%dD%d", &bus_idx, &addr) != 2) @@ -151,14 +169,7 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus, if (addr < 0 || addr > 31) return NULL; - list_for_each_entry(hlink, &bus->hlink_list, list) { - for (i = 0; i < HDA_MAX_CODECS; i++) { - if (hlink->lsdiid & (0x1 << addr)) - return hlink; - } - } - - return NULL; + return snd_hdac_ext_bus_link_at(bus, addr); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_link); diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 454474ac5716..efe810af28c5 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -160,8 +160,8 @@ int snd_hdac_i915_init(struct hdac_bus *bus) if (!IS_ENABLED(CONFIG_MODULES) || !request_module("i915")) { /* 60s timeout */ - wait_for_completion_timeout(&acomp->master_bind_complete, - msecs_to_jiffies(60 * 1000)); + wait_for_completion_killable_timeout(&acomp->master_bind_complete, + msecs_to_jiffies(60 * 1000)); } } if (!acomp->ops) { diff --git a/sound/mips/snd-n64.c b/sound/mips/snd-n64.c index 463a6fe589eb..bff6d85b8fe2 100644 --- a/sound/mips/snd-n64.c +++ b/sound/mips/snd-n64.c @@ -289,8 +289,7 @@ static int __init n64audio_probe(struct platform_device *pdev) struct snd_card *card; struct snd_pcm *pcm; struct n64audio *priv; - struct resource *res; - int err; + int err, irq; err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, @@ -337,12 +336,12 @@ static int __init n64audio_probe(struct platform_device *pdev) strcpy(card->shortname, "N64 Audio"); strcpy(card->longname, "N64 Audio"); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) { err = -EINVAL; goto fail_dma_alloc; } - if (devm_request_irq(&pdev->dev, res->start, n64audio_isr, + if (devm_request_irq(&pdev->dev, irq, n64audio_isr, IRQF_SHARED, "N64 Audio", priv)) { err = -EBUSY; goto fail_dma_alloc; diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index f246e6094289..991b1c5d41d5 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -59,15 +59,15 @@ /* PCI function 0 registers, address = <val> + PCIBASE0 */ /************************************************************************************************/ -#define PTR 0x00 /* Indexed register set pointer register */ +#define CA0106_PTR 0x00 /* Indexed register set pointer register */ /* NOTE: The CHANNELNUM and ADDRESS words can */ /* be modified independently of each other. */ /* CNL[1:0], ADDR[27:16] */ -#define DATA 0x04 /* Indexed register set data register */ +#define CA0106_DATA 0x04 /* Indexed register set data register */ /* DATA[31:0] */ -#define IPR 0x08 /* Global interrupt pending register */ +#define CA0106_IPR 0x08 /* Global interrupt pending register */ /* Clear pending interrupts by writing a 1 to */ /* the relevant bits and zero to the other bits */ #define IPR_MIDI_RX_B 0x00020000 /* MIDI UART-B Receive buffer non-empty */ @@ -88,7 +88,7 @@ #define IPR_MIDI_TX_A 0x00000002 /* MIDI UART-A Transmit buffer empty */ #define IPR_PCI 0x00000001 /* PCI Bus error */ -#define INTE 0x0c /* Interrupt enable register */ +#define CA0106_INTE 0x0c /* Interrupt enable register */ #define INTE_MIDI_RX_B 0x00020000 /* MIDI UART-B Receive buffer non-empty */ #define INTE_MIDI_TX_B 0x00010000 /* MIDI UART-B Transmit buffer empty */ @@ -108,8 +108,8 @@ #define INTE_MIDI_TX_A 0x00000002 /* MIDI UART-A Transmit buffer empty */ #define INTE_PCI 0x00000001 /* PCI Bus error */ -#define UNKNOWN10 0x10 /* Unknown ??. Defaults to 0 */ -#define HCFG 0x14 /* Hardware config register */ +#define CA0106_UNKNOWN10 0x10 /* Unknown ??. Defaults to 0 */ +#define CA0106_HCFG 0x14 /* Hardware config register */ /* 0x1000 causes AC3 to fails. It adds a dither bit. */ #define HCFG_STAC 0x10000000 /* Special mode for STAC9460 Codec. */ @@ -133,7 +133,7 @@ #define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */ /* Should be set to 1 when the EMU10K1 is */ /* completely initialized. */ -#define GPIO 0x18 /* Defaults: 005f03a3-Analog, 005f02a2-SPDIF. */ +#define CA0106_GPIO 0x18 /* Defaults: 005f03a3-Analog, 005f02a2-SPDIF. */ /* Here pins 0,1,2,3,4,,6 are output. 5,7 are input */ /* For the Audigy LS, pin 0 (or bit 8) controls the SPDIF/Analog jack. */ /* SB Live 24bit: @@ -152,9 +152,9 @@ * GPO [15:8] Default 0x9. (Default to SPDIF jack enabled for SPDIF) * GPO Enable [23:16] Default 0x0f. Setting a bit to 1, causes the pin to be an output pin. */ -#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */ +#define CA0106_AC97DATA 0x1c /* AC97 register set data register (16 bit) */ -#define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */ +#define CA0106_AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */ /********************************************************************************************************/ /* CA0106 pointer-offset register set, accessed through the PTR and DATA registers */ diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 36fb150b72fb..8577f9fa5ea6 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -338,8 +338,8 @@ unsigned int snd_ca0106_ptr_read(struct snd_ca0106 * emu, regptr = (reg << 16) | chn; spin_lock_irqsave(&emu->emu_lock, flags); - outl(regptr, emu->port + PTR); - val = inl(emu->port + DATA); + outl(regptr, emu->port + CA0106_PTR); + val = inl(emu->port + CA0106_DATA); spin_unlock_irqrestore(&emu->emu_lock, flags); return val; } @@ -355,8 +355,8 @@ void snd_ca0106_ptr_write(struct snd_ca0106 *emu, regptr = (reg << 16) | chn; spin_lock_irqsave(&emu->emu_lock, flags); - outl(regptr, emu->port + PTR); - outl(data, emu->port + DATA); + outl(regptr, emu->port + CA0106_PTR); + outl(data, emu->port + CA0106_DATA); spin_unlock_irqrestore(&emu->emu_lock, flags); } @@ -455,8 +455,8 @@ static void snd_ca0106_intr_enable(struct snd_ca0106 *emu, unsigned int intrenb) unsigned int intr_enable; spin_lock_irqsave(&emu->emu_lock, flags); - intr_enable = inl(emu->port + INTE) | intrenb; - outl(intr_enable, emu->port + INTE); + intr_enable = inl(emu->port + CA0106_INTE) | intrenb; + outl(intr_enable, emu->port + CA0106_INTE); spin_unlock_irqrestore(&emu->emu_lock, flags); } @@ -466,8 +466,8 @@ static void snd_ca0106_intr_disable(struct snd_ca0106 *emu, unsigned int intrenb unsigned int intr_enable; spin_lock_irqsave(&emu->emu_lock, flags); - intr_enable = inl(emu->port + INTE) & ~intrenb; - outl(intr_enable, emu->port + INTE); + intr_enable = inl(emu->port + CA0106_INTE) & ~intrenb; + outl(intr_enable, emu->port + CA0106_INTE); spin_unlock_irqrestore(&emu->emu_lock, flags); } @@ -786,9 +786,9 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream) hcfg_set = 0; break; } - hcfg = inl(emu->port + HCFG) ; + hcfg = inl(emu->port + CA0106_HCFG) ; hcfg = (hcfg & ~hcfg_mask) | hcfg_set; - outl(hcfg, emu->port + HCFG); + outl(hcfg, emu->port + CA0106_HCFG); reg40 = snd_ca0106_ptr_read(emu, 0x40, 0); reg40 = (reg40 & ~reg40_mask) | reg40_set; snd_ca0106_ptr_write(emu, 0x40, 0, reg40); @@ -888,9 +888,9 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream) hcfg_set = 0; break; } - hcfg = inl(emu->port + HCFG) ; + hcfg = inl(emu->port + CA0106_HCFG) ; hcfg = (hcfg & ~hcfg_mask) | hcfg_set; - outl(hcfg, emu->port + HCFG); + outl(hcfg, emu->port + CA0106_HCFG); reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); reg71 = (reg71 & ~reg71_mask) | reg71_set; snd_ca0106_ptr_write(emu, 0x71, 0, reg71); @@ -1142,8 +1142,8 @@ static unsigned short snd_ca0106_ac97_read(struct snd_ac97 *ac97, unsigned short val; spin_lock_irqsave(&emu->emu_lock, flags); - outb(reg, emu->port + AC97ADDRESS); - val = inw(emu->port + AC97DATA); + outb(reg, emu->port + CA0106_AC97ADDRESS); + val = inw(emu->port + CA0106_AC97DATA); spin_unlock_irqrestore(&emu->emu_lock, flags); return val; } @@ -1155,8 +1155,8 @@ static void snd_ca0106_ac97_write(struct snd_ac97 *ac97, unsigned long flags; spin_lock_irqsave(&emu->emu_lock, flags); - outb(reg, emu->port + AC97ADDRESS); - outw(val, emu->port + AC97DATA); + outb(reg, emu->port + CA0106_AC97ADDRESS); + outw(val, emu->port + CA0106_AC97DATA); spin_unlock_irqrestore(&emu->emu_lock, flags); } @@ -1200,7 +1200,7 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) unsigned int stat76; struct snd_ca0106_channel *pchannel; - status = inl(chip->port + IPR); + status = inl(chip->port + CA0106_IPR); if (! status) return IRQ_NONE; @@ -1255,7 +1255,7 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) } // acknowledge the interrupt if necessary - outl(status, chip->port+IPR); + outl(status, chip->port + CA0106_IPR); return IRQ_HANDLED; } @@ -1383,7 +1383,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) int ch; unsigned int def_bits; - outl(0, chip->port + INTE); + outl(0, chip->port + CA0106_INTE); /* * Init to 0x02109204 : @@ -1420,8 +1420,8 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); /* Write 0x8000 to AC97_REC_GAIN to mute it. */ - outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); - outw(0x8000, chip->port + AC97DATA); + outb(AC97_REC_GAIN, chip->port + CA0106_AC97ADDRESS); + outw(0x8000, chip->port + CA0106_AC97DATA); #if 0 /* FIXME: what are these? */ snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); @@ -1495,30 +1495,30 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) /* FIXME: Still need to find out what the other GPIO bits do. * E.g. For digital spdif out. */ - outl(0x0, chip->port+GPIO); - /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ - outl(0x005f5301, chip->port+GPIO); /* Analog */ + outl(0x0, chip->port + CA0106_GPIO); + /* outl(0x00f0e000, chip->port + CA0106_GPIO); */ /* Analog */ + outl(0x005f5301, chip->port + CA0106_GPIO); /* Analog */ } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. * E.g. For digital spdif out. */ - outl(0x0, chip->port+GPIO); - /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ - outl(0x005f5301, chip->port+GPIO); /* Analog */ + outl(0x0, chip->port + CA0106_GPIO); + /* outl(0x00f0e000, chip->port + CA0106_GPIO); */ /* Analog */ + outl(0x005f5301, chip->port + CA0106_GPIO); /* Analog */ } else { - outl(0x0, chip->port+GPIO); - outl(0x005f03a3, chip->port+GPIO); /* Analog */ - /* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */ + outl(0x0, chip->port + CA0106_GPIO); + outl(0x005f03a3, chip->port + CA0106_GPIO); /* Analog */ + /* outl(0x005f02a2, chip->port + CA0106_GPIO); */ /* SPDIF */ } snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ /* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */ /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ - /* outl(0x00001409, chip->port+HCFG); */ - /* outl(0x00000009, chip->port+HCFG); */ + /* outl(0x00001409, chip->port + CA0106_HCFG); */ + /* outl(0x00000009, chip->port + CA0106_HCFG); */ /* AC97 2.0, Enable outputs. */ - outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); + outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port + CA0106_HCFG); if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ @@ -1560,12 +1560,12 @@ static void ca0106_stop_chip(struct snd_ca0106 *chip) { /* disable interrupts */ snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); - outl(0, chip->port + INTE); + outl(0, chip->port + CA0106_INTE); snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); udelay(1000); /* disable audio */ /* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */ - outl(0, chip->port + HCFG); + outl(0, chip->port + CA0106_HCFG); /* FIXME: We need to stop and DMA transfers here. * But as I am not sure how yet, we cannot from the dma pages. * So we can fix: snd-malloc: Memory leak? pages not freed = 8 diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index c852c6a75b91..05f56015ddd8 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -70,8 +70,8 @@ static void ca0106_spdif_enable(struct snd_ca0106 *emu) snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); - val = inl(emu->port + GPIO) & ~0x101; - outl(val, emu->port + GPIO); + val = inl(emu->port + CA0106_GPIO) & ~0x101; + outl(val, emu->port + CA0106_GPIO); } else { /* Analog */ @@ -79,8 +79,8 @@ static void ca0106_spdif_enable(struct snd_ca0106 *emu) snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); - val = inl(emu->port + GPIO) | 0x101; - outl(val, emu->port + GPIO); + val = inl(emu->port + CA0106_GPIO) | 0x101; + outl(val, emu->port + CA0106_GPIO); } } @@ -119,14 +119,14 @@ static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) if (emu->capture_mic_line_in) { /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ - tmp = inl(emu->port+GPIO) & ~0x400; + tmp = inl(emu->port + CA0106_GPIO) & ~0x400; tmp = tmp | 0x400; - outl(tmp, emu->port+GPIO); + outl(tmp, emu->port + CA0106_GPIO); /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */ } else { /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ - tmp = inl(emu->port+GPIO) & ~0x400; - outl(tmp, emu->port+GPIO); + tmp = inl(emu->port + CA0106_GPIO) & ~0x400; + outl(tmp, emu->port + CA0106_GPIO); /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */ } } diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index cb72d27e809e..7be5c3327b16 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -208,7 +208,7 @@ static void snd_echo_midi_output_write(struct timer_list *t) /* No interrupts are involved: we have to check at regular intervals if the card's output buffer has room for new data. */ - sent = bytes = 0; + sent = 0; spin_lock_irqsave(&chip->lock, flags); chip->midi_full = 0; if (!snd_rawmidi_transmit_empty(chip->midi_out)) { diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index febe1c2b7d9a..9f6c99c1d87b 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -285,15 +285,16 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM bool "Enable Silent Stream always for HDMI" depends on SND_HDA_INTEL help - Intel hardware has a feature called 'silent stream', that - keeps external HDMI receiver's analog circuitry powered on - avoiding 2-3 sec silence during playback start. This mechanism - relies on setting channel_id as 0xf, sending info packet and - preventing codec D3 entry (increasing platform static power - consumption when HDMI receiver is plugged-in). 2-3 sec silence - at the playback start is expected whenever there is format change. - (default is 2 channel format). - Say Y to enable Silent Stream feature. + Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream + for HDMI on hardware that supports the feature. + + When enabled, the HDMI/DisplayPort codec will continue to provide + a continuous clock and a valid but silent data stream to + any connected external receiver. This allows to avoid gaps + at start of playback. Many receivers require multiple seconds + to start playing audio after the clock has been stopped. + This feature can impact power consumption as resources + are kept reserved both at transmitter and receiver. endif diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f552785d301e..5cbac315dbe1 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -766,6 +766,10 @@ static void codec_release_pcms(struct hda_codec *codec) } } +/** + * snd_hda_codec_cleanup_for_unbind - Prepare codec for removal + * @codec: codec device to cleanup + */ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) { if (codec->registered) { @@ -813,7 +817,12 @@ void snd_hda_codec_display_power(struct hda_codec *codec, bool enable) snd_hdac_display_power(&codec->bus->core, codec->addr, enable); } -/* also called from hda_bind.c */ +/** + * snd_hda_codec_register - Finalize codec initialization + * @codec: codec device to register + * + * Also called from hda_bind.c + */ void snd_hda_codec_register(struct hda_codec *codec) { if (codec->registered) @@ -826,6 +835,7 @@ void snd_hda_codec_register(struct hda_codec *codec) codec->registered = 1; } } +EXPORT_SYMBOL_GPL(snd_hda_codec_register); static int snd_hda_codec_dev_register(struct snd_device *device) { @@ -833,10 +843,12 @@ static int snd_hda_codec_dev_register(struct snd_device *device) return 0; } -static int snd_hda_codec_dev_free(struct snd_device *device) +/** + * snd_hda_codec_unregister - Unregister specified codec device + * @codec: codec device to unregister + */ +void snd_hda_codec_unregister(struct hda_codec *codec) { - struct hda_codec *codec = device->device_data; - codec->in_freeing = 1; /* * snd_hda_codec_device_new() is used by legacy HDA and ASoC driver. @@ -853,7 +865,12 @@ static int snd_hda_codec_dev_free(struct snd_device *device) */ if (codec->core.type == HDA_DEV_LEGACY) put_device(hda_codec_dev(codec)); +} +EXPORT_SYMBOL_GPL(snd_hda_codec_unregister); +static int snd_hda_codec_dev_free(struct snd_device *device) +{ + snd_hda_codec_unregister(device->device_data); return 0; } @@ -877,36 +894,48 @@ static void snd_hda_codec_dev_release(struct device *dev) #define DEV_NAME_LEN 31 -static int snd_hda_codec_device_init(struct hda_bus *bus, struct snd_card *card, - unsigned int codec_addr, struct hda_codec **codecp) +/** + * snd_hda_codec_device_init - allocate HDA codec device + * @bus: codec's parent bus + * @codec_addr: the codec address on the parent bus + * @fmt: format string for the device's name + * + * Returns newly allocated codec device or ERR_PTR() on failure. + */ +struct hda_codec * +snd_hda_codec_device_init(struct hda_bus *bus, unsigned int codec_addr, + const char *fmt, ...) { + va_list vargs; char name[DEV_NAME_LEN]; struct hda_codec *codec; int err; - dev_dbg(card->dev, "%s: entry\n", __func__); - if (snd_BUG_ON(!bus)) - return -EINVAL; + return ERR_PTR(-EINVAL); if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS)) - return -EINVAL; + return ERR_PTR(-EINVAL); codec = kzalloc(sizeof(*codec), GFP_KERNEL); if (!codec) - return -ENOMEM; + return ERR_PTR(-ENOMEM); + + va_start(vargs, fmt); + vsprintf(name, fmt, vargs); + va_end(vargs); - sprintf(name, "hdaudioC%dD%d", card->number, codec_addr); err = snd_hdac_device_init(&codec->core, &bus->core, name, codec_addr); if (err < 0) { kfree(codec); - return err; + return ERR_PTR(err); } + codec->bus = bus; codec->core.type = HDA_DEV_LEGACY; - *codecp = codec; - return err; + return codec; } +EXPORT_SYMBOL_GPL(snd_hda_codec_device_init); /** * snd_hda_codec_new - create a HDA codec @@ -920,18 +949,21 @@ static int snd_hda_codec_device_init(struct hda_bus *bus, struct snd_card *card, int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, unsigned int codec_addr, struct hda_codec **codecp) { - int ret; + struct hda_codec *codec; - ret = snd_hda_codec_device_init(bus, card, codec_addr, codecp); - if (ret < 0) - return ret; + codec = snd_hda_codec_device_init(bus, codec_addr, "hdaudioC%dD%d", + card->number, codec_addr); + if (IS_ERR(codec)) + return PTR_ERR(codec); + *codecp = codec; - return snd_hda_codec_device_new(bus, card, codec_addr, *codecp); + return snd_hda_codec_device_new(bus, card, codec_addr, *codecp, true); } EXPORT_SYMBOL_GPL(snd_hda_codec_new); int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, - unsigned int codec_addr, struct hda_codec *codec) + unsigned int codec_addr, struct hda_codec *codec, + bool snddev_managed) { char component[31]; hda_nid_t fg; @@ -951,7 +983,6 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, codec->core.dev.release = snd_hda_codec_dev_release; codec->core.exec_verb = codec_exec_verb; - codec->bus = bus; codec->card = card; codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); @@ -1007,9 +1038,12 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, codec->core.subsystem_id, codec->core.revision_id); snd_component_add(card, component); - err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops); - if (err < 0) - goto error; + if (snddev_managed) { + /* ASoC features component management instead */ + err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops); + if (err < 0) + goto error; + } /* PM runtime needs to be enabled later after binding codec */ pm_runtime_forbid(&codec->core.dev); @@ -3371,7 +3405,12 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); #ifdef CONFIG_PM -static void codec_set_power_save(struct hda_codec *codec, int delay) +/** + * snd_hda_codec_set_power_save - Configure codec's runtime PM + * @codec: codec device to configure + * @delay: autosuspend delay + */ +void snd_hda_codec_set_power_save(struct hda_codec *codec, int delay) { struct device *dev = hda_codec_dev(codec); @@ -3389,6 +3428,7 @@ static void codec_set_power_save(struct hda_codec *codec, int delay) pm_runtime_forbid(dev); } } +EXPORT_SYMBOL_GPL(snd_hda_codec_set_power_save); /** * snd_hda_set_power_save - reprogram autosuspend for the given delay @@ -3402,7 +3442,7 @@ void snd_hda_set_power_save(struct hda_bus *bus, int delay) struct hda_codec *c; list_for_each_codec(c, bus) - codec_set_power_save(c, delay); + snd_hda_codec_set_power_save(c, delay); } EXPORT_SYMBOL_GPL(snd_hda_set_power_save); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 572ff0d1fafe..0a83eb6b88b1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2066,14 +2066,16 @@ static const struct hda_controller_ops pci_hda_ops = { .position_check = azx_position_check, }; +static DECLARE_BITMAP(probed_devs, SNDRV_CARDS); + static int azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; struct snd_card *card; struct hda_intel *hda; struct azx *chip; bool schedule_probe; + int dev; int err; if (pci_match_id(driver_denylist, pci)) { @@ -2081,10 +2083,11 @@ static int azx_probe(struct pci_dev *pci, return -ENODEV; } + dev = find_first_zero_bit(probed_devs, SNDRV_CARDS); if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { - dev++; + set_bit(dev, probed_devs); return -ENOENT; } @@ -2151,7 +2154,7 @@ static int azx_probe(struct pci_dev *pci, if (schedule_probe) schedule_delayed_work(&hda->probe_work, 0); - dev++; + set_bit(dev, probed_devs); if (chip->disabled) complete_all(&hda->probe_wait); return 0; @@ -2374,6 +2377,7 @@ static void azx_remove(struct pci_dev *pci) cancel_delayed_work_sync(&hda->probe_work); device_lock(&pci->dev); + clear_bit(chip->dev_index, probed_devs); pci_set_drvdata(pci, NULL); snd_card_free(card); } @@ -2495,6 +2499,8 @@ static const struct pci_device_id azx_ids[] = { /* Alderlake-P */ { PCI_DEVICE(0x8086, 0x51c8), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE(0x8086, 0x51c9), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, { PCI_DEVICE(0x8086, 0x51cd), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Alderlake-M */ @@ -2508,6 +2514,17 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, { PCI_DEVICE(0x8086, 0x4b58), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + /* Raptor Lake */ + { PCI_DEVICE(0x8086, 0x7a50), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE(0x8086, 0x51ca), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE(0x8086, 0x51cb), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE(0x8086, 0x51ce), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE(0x8086, 0x51cf), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8621f576446b..aca592651870 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -135,8 +135,6 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, #define snd_hda_add_vmaster(codec, name, tlv, followers, suffix, access) \ __snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, access, NULL) int snd_hda_codec_reset(struct hda_codec *codec); -void snd_hda_codec_register(struct hda_codec *codec); -void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec); void snd_hda_codec_disconnect_pcms(struct hda_codec *codec); #define snd_hda_regmap_sync(codec) snd_hdac_regmap_sync(&(codec)->core) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 773f4903550a..2347d0304f93 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -70,6 +70,7 @@ struct hda_tegra_soc { bool has_hda2codec_2x_reset; + bool has_hda2hdmi; }; struct hda_tegra { @@ -314,6 +315,18 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) * hardcoded value */ chip->capture_streams = (gcap >> 8) & 0x0f; + + /* The GCAP register on Tegra234 implies no Input Streams(ISS) support, + * but the HW output stream descriptor programming should start with + * offset 0x20*4 from base stream descriptor address. This will be a + * problem while calculating the offset for output stream descriptor + * which will be considering input stream also. So here output stream + * starts with offset 0 which is wrong as HW register for output stream + * offset starts with 4. + */ + if (of_device_is_compatible(np, "nvidia,tegra234-hda")) + chip->capture_streams = 4; + chip->playback_streams = (gcap >> 12) & 0x0f; if (!chip->playback_streams && !chip->capture_streams) { /* gcap didn't give any info, switching to old method */ @@ -435,15 +448,23 @@ static int hda_tegra_create(struct snd_card *card, static const struct hda_tegra_soc tegra30_data = { .has_hda2codec_2x_reset = true, + .has_hda2hdmi = true, }; static const struct hda_tegra_soc tegra194_data = { .has_hda2codec_2x_reset = false, + .has_hda2hdmi = true, +}; + +static const struct hda_tegra_soc tegra234_data = { + .has_hda2codec_2x_reset = true, + .has_hda2hdmi = false, }; static const struct of_device_id hda_tegra_match[] = { { .compatible = "nvidia,tegra30-hda", .data = &tegra30_data }, { .compatible = "nvidia,tegra194-hda", .data = &tegra194_data }, + { .compatible = "nvidia,tegra234-hda", .data = &tegra234_data }, {}, }; MODULE_DEVICE_TABLE(of, hda_tegra_match); @@ -473,7 +494,14 @@ static int hda_tegra_probe(struct platform_device *pdev) } hda->resets[hda->nresets++].id = "hda"; - hda->resets[hda->nresets++].id = "hda2hdmi"; + + /* + * "hda2hdmi" is not applicable for Tegra234. This is because the + * codec is separate IP and not under display SOR partition now. + */ + if (hda->soc->has_hda2hdmi) + hda->resets[hda->nresets++].id = "hda2hdmi"; + /* * "hda2codec_2x" reset is not present on Tegra194. Though DT would * be updated to reflect this, but to have backward compatibility @@ -488,7 +516,8 @@ static int hda_tegra_probe(struct platform_device *pdev) goto out_free; hda->clocks[hda->nclocks++].id = "hda"; - hda->clocks[hda->nclocks++].id = "hda2hdmi"; + if (hda->soc->has_hda2hdmi) + hda->clocks[hda->nclocks++].id = "hda2hdmi"; hda->clocks[hda->nclocks++].id = "hda2codec_2x"; err = devm_clk_bulk_get(&pdev->dev, hda->nclocks, hda->clocks); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 92df4f243ec6..c85ed7bc121e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -120,6 +120,12 @@ struct hdmi_pcm { struct snd_kcontrol *eld_ctl; }; +enum { + SILENT_STREAM_OFF = 0, + SILENT_STREAM_KAE, /* use standard HDA Keep-Alive */ + SILENT_STREAM_I915, /* Intel i915 extension */ +}; + struct hdmi_spec { struct hda_codec *codec; int num_cvts; @@ -162,6 +168,8 @@ struct hdmi_spec { bool dyn_pin_out; bool dyn_pcm_assign; bool dyn_pcm_no_legacy; + /* hdmi interrupt trigger control flag for Nvidia codec */ + bool hdmi_intr_trig_ctrl; bool intel_hsw_fixup; /* apply Intel platform-specific fixups */ /* * Non-generic VIA/NVIDIA specific @@ -179,7 +187,7 @@ struct hdmi_spec { hda_nid_t vendor_nid; const int *port_map; int port_num; - bool send_silent_stream; /* Flag to enable silent stream feature */ + int silent_stream_type; }; #ifdef CONFIG_SND_HDA_COMPONENT @@ -1665,18 +1673,71 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, #define I915_SILENT_FORMAT_BITS 16 #define I915_SILENT_FMT_MASK 0xf +static void silent_stream_enable_i915(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + unsigned int format; + + snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid, + per_pin->dev_id, I915_SILENT_RATE); + + /* trigger silent stream generation in hw */ + format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS, + I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0); + snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, + I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format); + usleep_range(100, 200); + snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format); + + per_pin->channels = I915_SILENT_CHANNELS; + hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); +} + +static void silent_stream_set_kae(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + bool enable) +{ + unsigned int param; + + codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid); + + param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); + param = (param >> 16) & 0xff; + + if (enable) + param |= AC_DIG3_KAE; + else + param &= ~AC_DIG3_KAE; + + snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param); +} + static void silent_stream_enable(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin) { struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_cvt *per_cvt; int cvt_idx, pin_idx, err; - unsigned int format; + int keep_power = 0; + + /* + * Power-up will call hdmi_present_sense, so the PM calls + * have to be done without mutex held. + */ + + err = snd_hda_power_up_pm(codec); + if (err < 0 && err != -EACCES) { + codec_err(codec, + "Failed to power up codec for silent stream enable ret=[%d]\n", err); + snd_hda_power_down_pm(codec); + return; + } mutex_lock(&per_pin->lock); if (per_pin->setup) { codec_dbg(codec, "hdmi: PCM already open, no silent stream\n"); + err = -EBUSY; goto unlock_out; } @@ -1703,22 +1764,23 @@ static void silent_stream_enable(struct hda_codec *codec, /* configure unused pins to choose other converters */ pin_cvt_fixup(codec, per_pin, 0); - snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid, - per_pin->dev_id, I915_SILENT_RATE); - - /* trigger silent stream generation in hw */ - format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS, - I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0); - snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, - I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format); - usleep_range(100, 200); - snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format); - - per_pin->channels = I915_SILENT_CHANNELS; - hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + switch (spec->silent_stream_type) { + case SILENT_STREAM_KAE: + silent_stream_set_kae(codec, per_pin, true); + break; + case SILENT_STREAM_I915: + silent_stream_enable_i915(codec, per_pin); + keep_power = 1; + break; + default: + break; + } unlock_out: mutex_unlock(&per_pin->lock); + + if (err || !keep_power) + snd_hda_power_down_pm(codec); } static void silent_stream_disable(struct hda_codec *codec, @@ -1726,7 +1788,16 @@ static void silent_stream_disable(struct hda_codec *codec, { struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_cvt *per_cvt; - int cvt_idx; + int cvt_idx, err; + + err = snd_hda_power_up_pm(codec); + if (err < 0 && err != -EACCES) { + codec_err(codec, + "Failed to power up codec for silent stream disable ret=[%d]\n", + err); + snd_hda_power_down_pm(codec); + return; + } mutex_lock(&per_pin->lock); if (!per_pin->silent_stream) @@ -1741,11 +1812,20 @@ static void silent_stream_disable(struct hda_codec *codec, per_cvt->assigned = 0; } + if (spec->silent_stream_type == SILENT_STREAM_I915) { + /* release ref taken in silent_stream_enable() */ + snd_hda_power_down_pm(codec); + } else if (spec->silent_stream_type == SILENT_STREAM_KAE) { + silent_stream_set_kae(codec, per_pin, false); + } + per_pin->cvt_nid = 0; per_pin->silent_stream = false; unlock_out: mutex_unlock(&per_pin->lock); + + snd_hda_power_down_pm(codec); } /* update ELD and jack state via audio component */ @@ -1767,29 +1847,11 @@ static void sync_eld_via_acomp(struct hda_codec *codec, monitor_next = per_pin->sink_eld.monitor_present; mutex_unlock(&per_pin->lock); - /* - * Power-up will call hdmi_present_sense, so the PM calls - * have to be done without mutex held. - */ - - if (spec->send_silent_stream) { - int pm_ret; - - if (!monitor_prev && monitor_next) { - pm_ret = snd_hda_power_up_pm(codec); - if (pm_ret < 0) - codec_err(codec, - "Monitor plugged-in, Failed to power up codec ret=[%d]\n", - pm_ret); + if (spec->silent_stream_type) { + if (!monitor_prev && monitor_next) silent_stream_enable(codec, per_pin); - } else if (monitor_prev && !monitor_next) { + else if (monitor_prev && !monitor_next) silent_stream_disable(codec, per_pin); - pm_ret = snd_hda_power_down_pm(codec); - if (pm_ret < 0) - codec_err(codec, - "Monitor plugged-out, Failed to power down codec ret=[%d]\n", - pm_ret); - } } } @@ -2982,7 +3044,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, * module param or Kconfig option */ if (send_silent_stream) - spec->send_silent_stream = true; + spec->silent_stream_type = SILENT_STREAM_I915; return parse_intel_hdmi(codec); } @@ -3035,6 +3097,22 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec) return ret; } +static int patch_i915_adlp_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int res; + + res = patch_i915_tgl_hdmi(codec); + if (!res) { + spec = codec->spec; + + if (spec->silent_stream_type) + spec->silent_stream_type = SILENT_STREAM_KAE; + } + + return res; +} + /* Intel Baytrail and Braswell; with eld notifier */ static int patch_i915_byt_hdmi(struct hda_codec *codec) { @@ -3721,8 +3799,11 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec) * +-----------------------------------| * * Note that for the trigger bit to take effect it needs to change value - * (i.e. it needs to be toggled). + * (i.e. it needs to be toggled). The trigger bit is not applicable from + * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt + * trigger to hdmi. */ +#define NVIDIA_SET_HOST_INTR 0xf80 #define NVIDIA_GET_SCRATCH0 0xfa6 #define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7 #define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8 @@ -3741,25 +3822,38 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec) * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0, * the format is invalidated so that the HDMI codec can be disabled. */ -static void tegra_hdmi_set_format(struct hda_codec *codec, unsigned int format) +static void tegra_hdmi_set_format(struct hda_codec *codec, + hda_nid_t cvt_nid, + unsigned int format) { unsigned int value; + unsigned int nid = NVIDIA_AFG_NID; + struct hdmi_spec *spec = codec->spec; + + /* + * Tegra HDA codec design from TEGRA234 chip onwards support DP MST. + * This resulted in moving scratch registers from audio function + * group to converter widget context. So CVT NID should be used for + * scratch register read/write for DP MST supported Tegra HDA codec. + */ + if (codec->dp_mst) + nid = cvt_nid; /* bits [31:30] contain the trigger and valid bits */ - value = snd_hda_codec_read(codec, NVIDIA_AFG_NID, 0, + value = snd_hda_codec_read(codec, nid, 0, NVIDIA_GET_SCRATCH0, 0); value = (value >> 24) & 0xff; /* bits [15:0] are used to store the HDA format */ - snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + snd_hda_codec_write(codec, nid, 0, NVIDIA_SET_SCRATCH0_BYTE0, (format >> 0) & 0xff); - snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + snd_hda_codec_write(codec, nid, 0, NVIDIA_SET_SCRATCH0_BYTE1, (format >> 8) & 0xff); /* bits [16:24] are unused */ - snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + snd_hda_codec_write(codec, nid, 0, NVIDIA_SET_SCRATCH0_BYTE2, 0); /* @@ -3771,15 +3865,28 @@ static void tegra_hdmi_set_format(struct hda_codec *codec, unsigned int format) else value |= NVIDIA_SCRATCH_VALID; - /* - * Whenever the trigger bit is toggled, an interrupt is raised in the - * HDMI codec. The HDMI driver will use that as trigger to update its - * configuration. - */ - value ^= NVIDIA_SCRATCH_TRIGGER; + if (spec->hdmi_intr_trig_ctrl) { + /* + * For Tegra HDA Codec design from TEGRA234 onwards, the + * Interrupt to hdmi driver is triggered by writing + * non-zero values to verb 0xF80 instead of 31st bit of + * scratch register. + */ + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE3, value); + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_HOST_INTR, 0x1); + } else { + /* + * Whenever the 31st trigger bit is toggled, an interrupt is raised + * in the HDMI codec. The HDMI driver will use that as trigger + * to update its configuration. + */ + value ^= NVIDIA_SCRATCH_TRIGGER; - snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, - NVIDIA_SET_SCRATCH0_BYTE3, value); + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE3, value); + } } static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -3796,7 +3903,7 @@ static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo, return err; /* notify the HDMI codec of the format change */ - tegra_hdmi_set_format(codec, format); + tegra_hdmi_set_format(codec, hinfo->nid, format); return 0; } @@ -3806,7 +3913,7 @@ static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { /* invalidate the format in the HDMI codec */ - tegra_hdmi_set_format(codec, 0); + tegra_hdmi_set_format(codec, hinfo->nid, 0); return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream); } @@ -3851,17 +3958,29 @@ static int tegra_hdmi_build_pcms(struct hda_codec *codec) return 0; } -static int patch_tegra_hdmi(struct hda_codec *codec) +static int tegra_hdmi_init(struct hda_codec *codec) { - struct hdmi_spec *spec; - int err; + struct hdmi_spec *spec = codec->spec; + int i, err; - err = patch_generic_hdmi(codec); - if (err) + err = hdmi_parse_codec(codec); + if (err < 0) { + generic_spec_free(codec); return err; + } + + for (i = 0; i < spec->num_cvts; i++) + snd_hda_codec_write(codec, spec->cvt_nids[i], 0, + AC_VERB_SET_DIGI_CONVERT_1, + AC_DIG1_ENABLE); + + generic_hdmi_init_per_pins(codec); codec->patch_ops.build_pcms = tegra_hdmi_build_pcms; - spec = codec->spec; + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + nvhdmi_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + spec->chmap.ops.chmap_cea_alloc_validate_get_type = nvhdmi_chmap_cea_alloc_validate_get_type; spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; @@ -3869,6 +3988,36 @@ static int patch_tegra_hdmi(struct hda_codec *codec) return 0; } +static int patch_tegra_hdmi(struct hda_codec *codec) +{ + int err; + + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + + return tegra_hdmi_init(codec); +} + +static int patch_tegra234_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + + codec->dp_mst = true; + codec->mst_no_extra_pcms = true; + spec = codec->spec; + spec->dyn_pin_out = true; + spec->dyn_pcm_assign = true; + spec->hdmi_intr_trig_ctrl = true; + + return tegra_hdmi_init(codec); +} + /* * ATI/AMD-specific implementations */ @@ -4322,6 +4471,7 @@ HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi), HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi), @@ -4390,10 +4540,11 @@ HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi), -HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), -HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 75ff7e8498b8..1d14be4ee31d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6662,6 +6662,16 @@ static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2); } +static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action) +{ + cs35l41_generic_fixup(codec, action, "spi0", "CSC3551", 2); +} + +static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action) +{ + cs35l41_generic_fixup(codec, action, "spi0", "CSC3551", 4); +} + static void alc287_legion_16achg6_playback_hook(struct hda_pcm_stream *hinfo, struct hda_codec *cdc, struct snd_pcm_substream *sub, int action) { @@ -6999,6 +7009,9 @@ enum { ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE, ALC287_FIXUP_LEGION_16ACHG6, ALC287_FIXUP_CS35L41_I2C_2, + ALC245_FIXUP_CS35L41_SPI_2, + ALC245_FIXUP_CS35L41_SPI_4, + ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED, ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED, }; @@ -8750,6 +8763,20 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = cs35l41_fixup_i2c_two, }, + [ALC245_FIXUP_CS35L41_SPI_2] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_spi_two, + }, + [ALC245_FIXUP_CS35L41_SPI_4] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_spi_four, + }, + [ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_spi_four, + .chained = true, + .chain_id = ALC285_FIXUP_HP_GPIO_LED, + }, [ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -8977,7 +9004,25 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x89c3, "HP", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x896e, "HP EliteBook x360 830 G9", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8971, "HP EliteBook 830 G9", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8972, "HP EliteBook 840 G9", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8973, "HP EliteBook 860 G9", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8974, "HP EliteBook 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8975, "HP EliteBook x360 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8981, "HP Elite Dragonfly G3", ALC245_FIXUP_CS35L41_SPI_4), + SND_PCI_QUIRK(0x103c, 0x898e, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x898f, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8991, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8992, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8994, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8995, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x89a4, "HP ProBook 440 G9", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x89a6, "HP ProBook 450 G9", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x89ac, "HP EliteBook 640 G9", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x89ae, "HP EliteBook 650 G9", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x89c3, "Zbook Studio G9", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c index e2c8f1417001..6b162489cb5f 100644 --- a/sound/pci/lola/lola_mixer.c +++ b/sound/pci/lola/lola_mixer.c @@ -121,6 +121,8 @@ int lola_init_mixer_widget(struct lola *chip, int nid) /* reserve memory to copy mixer data for sleep mode transitions */ chip->mixer.array_saved = vmalloc(sizeof(struct lola_mixer_array)); + if (!chip->mixer.array_saved) + return -ENOMEM; /* mixer matrix sources are physical input data and play streams */ chip->mixer.src_stream_outs = chip->pcm[PLAY].num_streams; diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index de5955db0a5f..667f3df239c7 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -413,7 +413,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) HDA_CODEC_IDX_CONTROLLER, true); ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card, - hdev->addr, hcodec); + hdev->addr, hcodec, true); if (ret < 0) { dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); goto error_no_pm; diff --git a/sound/sound_core.c b/sound/sound_core.c index 90d118cd9164..3332fe321737 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -136,11 +136,7 @@ struct sound_unit * All these clutters are scheduled to be removed along with * sound-slot/service-* module aliases. */ -#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM -static int preclaim_oss = 1; -#else -static int preclaim_oss = 0; -#endif +static int preclaim_oss = IS_ENABLED(CONFIG_SOUND_OSS_CORE_PRECLAIM); module_param(preclaim_oss, int, 0444); @@ -581,20 +577,20 @@ static int soundcore_open(struct inode *inode, struct file *file) new_fops = fops_get(s->unit_fops); } spin_unlock(&sound_loader_lock); - if (new_fops) { - /* - * We rely upon the fact that we can't be unloaded while the - * subdriver is there. - */ - int err = 0; - replace_fops(file, new_fops); - if (file->f_op->open) - err = file->f_op->open(inode,file); + if (!new_fops) + return -ENODEV; - return err; - } - return -ENODEV; + /* + * We rely upon the fact that we can't be unloaded while the + * subdriver is there. + */ + replace_fops(file, new_fops); + + if (!file->f_op->open) + return -ENODEV; + + return file->f_op->open(inode, file); } MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR); diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 76c0e37a838c..8a2da6b1012e 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -218,7 +218,9 @@ static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream) runtime->hw = snd_at73c213_playback_hw; chip->substream = substream; - clk_enable(chip->ssc->clk); + err = clk_enable(chip->ssc->clk); + if (err) + return err; return 0; } @@ -776,7 +778,9 @@ static int snd_at73c213_chip_init(struct snd_at73c213 *chip) goto out; /* Enable DAC master clock. */ - clk_enable(chip->board->dac_clk); + retval = clk_enable(chip->board->dac_clk); + if (retval) + goto out; /* Initialize at73c213 on SPI bus. */ retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04); @@ -889,7 +893,9 @@ static int snd_at73c213_dev_init(struct snd_card *card, chip->card = card; chip->irq = -1; - clk_enable(chip->ssc->clk); + retval = clk_enable(chip->ssc->clk); + if (retval) + return retval; retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); if (retval) { @@ -1008,7 +1014,9 @@ static int snd_at73c213_remove(struct spi_device *spi) int retval; /* Stop playback. */ - clk_enable(chip->ssc->clk); + retval = clk_enable(chip->ssc->clk); + if (retval) + goto out; ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); clk_disable(chip->ssc->clk); @@ -1088,9 +1096,16 @@ static int snd_at73c213_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct snd_at73c213 *chip = card->private_data; + int retval; - clk_enable(chip->board->dac_clk); - clk_enable(chip->ssc->clk); + retval = clk_enable(chip->board->dac_clk); + if (retval) + return retval; + retval = clk_enable(chip->ssc->clk); + if (retval) { + clk_disable(chip->board->dac_clk); + return retval; + } ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); return 0; diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c index 0255089c9efb..fac4bbc6b275 100644 --- a/sound/usb/mixer_s1810c.c +++ b/sound/usb/mixer_s1810c.c @@ -221,7 +221,7 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) e = 0xbc; for (n = 0; n < 2; n++) { off = n * 18; - for (b = off, c = 0; b < 18 + off; b++) { + for (b = off; b < 18 + off; b++) { /* This channel to all outputs ? */ for (c = 0; c <= 8; c++) { snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 53ebabf42472..69a2cd429ee2 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -6,7 +6,7 @@ * - 6i6/18i8/18i20 Gen 2 * - Solo/2i2/4i4/8i6/18i8/18i20 Gen 3 * - * Copyright (c) 2018-2021 by Geoffrey D. Bennett <g at b4.vu> + * Copyright (c) 2018-2022 by Geoffrey D. Bennett <g at b4.vu> * Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com> * * Based on the Scarlett (Gen 1) Driver for ALSA: @@ -60,6 +60,7 @@ * - phantom power, direct monitor, speaker switching, and talkback * controls * - disable/enable MSD mode + * - disable/enable standalone mode * * <ditaa> * /--------------\ 18chn 20chn /--------------\ @@ -195,6 +196,16 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { /* Maximum number of meters (sum of output port counts) */ #define SCARLETT2_MAX_METERS 65 +/* There are three different sets of configuration parameters across + * the devices + */ +enum { + SCARLETT2_CONFIG_SET_NO_MIXER = 0, + SCARLETT2_CONFIG_SET_GEN_2 = 1, + SCARLETT2_CONFIG_SET_GEN_3 = 2, + SCARLETT2_CONFIG_SET_COUNT = 3 +}; + /* Hardware port types: * - None (no input to mux) * - Analogue I/O @@ -308,10 +319,8 @@ struct scarlett2_device_info { */ u8 has_msd_mode; - /* Gen 3 devices without a mixer have a different - * configuration set - */ - u8 has_mixer; + /* which set of configuration parameters the device uses */ + u8 config_set; /* line out hw volume is sw controlled */ u8 line_out_hw_vol; @@ -403,6 +412,7 @@ struct scarlett2_data { u8 talkback_switch; u8 talkback_map[SCARLETT2_OUTPUT_MIX_MAX]; u8 msd_switch; + u8 standalone_switch; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; @@ -426,7 +436,7 @@ struct scarlett2_data { static const struct scarlett2_device_info s6i6_gen2_info = { .usb_id = USB_ID(0x1235, 0x8203), - .has_mixer = 1, + .config_set = SCARLETT2_CONFIG_SET_GEN_2, .level_input_count = 2, .pad_input_count = 2, @@ -472,7 +482,7 @@ static const struct scarlett2_device_info s6i6_gen2_info = { static const struct scarlett2_device_info s18i8_gen2_info = { .usb_id = USB_ID(0x1235, 0x8204), - .has_mixer = 1, + .config_set = SCARLETT2_CONFIG_SET_GEN_2, .level_input_count = 2, .pad_input_count = 4, @@ -521,7 +531,7 @@ static const struct scarlett2_device_info s18i8_gen2_info = { static const struct scarlett2_device_info s18i20_gen2_info = { .usb_id = USB_ID(0x1235, 0x8201), - .has_mixer = 1, + .config_set = SCARLETT2_CONFIG_SET_GEN_2, .line_out_hw_vol = 1, .line_out_descrs = { @@ -576,6 +586,7 @@ static const struct scarlett2_device_info solo_gen3_info = { .usb_id = USB_ID(0x1235, 0x8211), .has_msd_mode = 1, + .config_set = SCARLETT2_CONFIG_SET_NO_MIXER, .level_input_count = 1, .level_input_first = 1, .air_input_count = 1, @@ -588,6 +599,7 @@ static const struct scarlett2_device_info s2i2_gen3_info = { .usb_id = USB_ID(0x1235, 0x8210), .has_msd_mode = 1, + .config_set = SCARLETT2_CONFIG_SET_NO_MIXER, .level_input_count = 2, .air_input_count = 2, .phantom_count = 1, @@ -599,7 +611,7 @@ static const struct scarlett2_device_info s4i4_gen3_info = { .usb_id = USB_ID(0x1235, 0x8212), .has_msd_mode = 1, - .has_mixer = 1, + .config_set = SCARLETT2_CONFIG_SET_GEN_3, .level_input_count = 2, .pad_input_count = 2, .air_input_count = 2, @@ -645,7 +657,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = { .usb_id = USB_ID(0x1235, 0x8213), .has_msd_mode = 1, - .has_mixer = 1, + .config_set = SCARLETT2_CONFIG_SET_GEN_3, .level_input_count = 2, .pad_input_count = 2, .air_input_count = 2, @@ -698,7 +710,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = { .usb_id = USB_ID(0x1235, 0x8214), .has_msd_mode = 1, - .has_mixer = 1, + .config_set = SCARLETT2_CONFIG_SET_GEN_3, .line_out_hw_vol = 1, .has_speaker_switching = 1, .level_input_count = 2, @@ -768,7 +780,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = { .usb_id = USB_ID(0x1235, 0x8215), .has_msd_mode = 1, - .has_mixer = 1, + .config_set = SCARLETT2_CONFIG_SET_GEN_3, .line_out_hw_vol = 1, .has_speaker_switching = 1, .has_talkback = 1, @@ -926,13 +938,14 @@ enum { SCARLETT2_CONFIG_PAD_SWITCH = 5, SCARLETT2_CONFIG_MSD_SWITCH = 6, SCARLETT2_CONFIG_AIR_SWITCH = 7, - SCARLETT2_CONFIG_PHANTOM_SWITCH = 8, - SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 9, - SCARLETT2_CONFIG_DIRECT_MONITOR = 10, - SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH = 11, - SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE = 12, - SCARLETT2_CONFIG_TALKBACK_MAP = 13, - SCARLETT2_CONFIG_COUNT = 14 + SCARLETT2_CONFIG_STANDALONE_SWITCH = 8, + SCARLETT2_CONFIG_PHANTOM_SWITCH = 9, + SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 10, + SCARLETT2_CONFIG_DIRECT_MONITOR = 11, + SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH = 12, + SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE = 13, + SCARLETT2_CONFIG_TALKBACK_MAP = 14, + SCARLETT2_CONFIG_COUNT = 15 }; /* Location, size, and activation command number for the configuration @@ -944,13 +957,11 @@ struct scarlett2_config { u8 activate; }; -/* scarlett2_config_items[0] is for devices without a mixer - * scarlett2_config_items[1] is for devices with a mixer - */ static const struct scarlett2_config - scarlett2_config_items[2][SCARLETT2_CONFIG_COUNT] = + scarlett2_config_items[SCARLETT2_CONFIG_SET_COUNT] + [SCARLETT2_CONFIG_COUNT] = -/* Devices without a mixer (Solo and 2i2 Gen 3) */ +/* Devices without a mixer (Gen 3 Solo and 2i2) */ { { [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x04, .size = 8, .activate = 6 }, @@ -970,7 +981,30 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_AIR_SWITCH] = { .offset = 0x09, .size = 1, .activate = 8 }, -/* Devices with a mixer (Gen 2 and all other Gen 3) */ +/* Gen 2 devices: 6i6, 18i8, 18i20 */ +}, { + [SCARLETT2_CONFIG_DIM_MUTE] = { + .offset = 0x31, .size = 8, .activate = 2 }, + + [SCARLETT2_CONFIG_LINE_OUT_VOLUME] = { + .offset = 0x34, .size = 16, .activate = 1 }, + + [SCARLETT2_CONFIG_MUTE_SWITCH] = { + .offset = 0x5c, .size = 8, .activate = 1 }, + + [SCARLETT2_CONFIG_SW_HW_SWITCH] = { + .offset = 0x66, .size = 8, .activate = 3 }, + + [SCARLETT2_CONFIG_LEVEL_SWITCH] = { + .offset = 0x7c, .size = 8, .activate = 7 }, + + [SCARLETT2_CONFIG_PAD_SWITCH] = { + .offset = 0x84, .size = 8, .activate = 8 }, + + [SCARLETT2_CONFIG_STANDALONE_SWITCH] = { + .offset = 0x8d, .size = 8, .activate = 6 }, + +/* Gen 3 devices: 4i4, 8i6, 18i8, 18i20 */ }, { [SCARLETT2_CONFIG_DIM_MUTE] = { .offset = 0x31, .size = 8, .activate = 2 }, @@ -993,6 +1027,9 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_AIR_SWITCH] = { .offset = 0x8c, .size = 8, .activate = 8 }, + [SCARLETT2_CONFIG_STANDALONE_SWITCH] = { + .offset = 0x95, .size = 8, .activate = 6 }, + [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { .offset = 0x9c, .size = 1, .activate = 8 }, @@ -1061,9 +1098,9 @@ static int scarlett2_usb( { struct scarlett2_data *private = mixer->private_data; struct usb_device *dev = mixer->chip->dev; - u16 req_buf_size = sizeof(struct scarlett2_usb_packet) + req_size; - u16 resp_buf_size = sizeof(struct scarlett2_usb_packet) + resp_size; struct scarlett2_usb_packet *req, *resp = NULL; + size_t req_buf_size = struct_size(req, data, req_size); + size_t resp_buf_size = struct_size(resp, data, resp_size); int err; req = kmalloc(req_buf_size, GFP_KERNEL); @@ -1111,7 +1148,7 @@ static int scarlett2_usb( usb_audio_err( mixer->chip, "Scarlett Gen 2/3 USB response result cmd %x was %d " - "expected %d\n", + "expected %zu\n", cmd, err, resp_buf_size); err = -EINVAL; goto unlock; @@ -1175,7 +1212,7 @@ static int scarlett2_usb_get_config( struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; const struct scarlett2_config *config_item = - &scarlett2_config_items[info->has_mixer][config_item_num]; + &scarlett2_config_items[info->config_set][config_item_num]; int size, err, i; u8 *buf_8; u8 value; @@ -1235,7 +1272,7 @@ static int scarlett2_usb_set_config( struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; const struct scarlett2_config *config_item = - &scarlett2_config_items[info->has_mixer][config_item_num]; + &scarlett2_config_items[info->config_set][config_item_num]; struct { __le32 offset; __le32 bytes; @@ -1692,7 +1729,7 @@ static int scarlett2_add_sync_ctl(struct usb_mixer_interface *mixer) struct scarlett2_data *private = mixer->private_data; /* devices without a mixer also don't support reporting sync status */ - if (!private->info->has_mixer) + if (private->info->config_set == SCARLETT2_CONFIG_SET_NO_MIXER) return 0; return scarlett2_add_new_ctl(mixer, &scarlett2_sync_ctl, @@ -3399,7 +3436,7 @@ static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer) struct scarlett2_data *private = mixer->private_data; /* devices without a mixer also don't support reporting levels */ - if (!private->info->has_mixer) + if (private->info->config_set == SCARLETT2_CONFIG_SET_NO_MIXER) return 0; return scarlett2_add_new_ctl(mixer, &scarlett2_meter_ctl, @@ -3474,6 +3511,69 @@ static int scarlett2_add_msd_ctl(struct usb_mixer_interface *mixer) 0, 1, "MSD Mode Switch", NULL); } +/*** Standalone Control ***/ + +static int scarlett2_standalone_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = private->standalone_switch; + return 0; +} + +static int scarlett2_standalone_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->standalone_switch; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->standalone_switch = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, + SCARLETT2_CONFIG_STANDALONE_SWITCH, + 0, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_standalone_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_standalone_ctl_get, + .put = scarlett2_standalone_ctl_put, +}; + +static int scarlett2_add_standalone_ctl(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + if (private->info->config_set == SCARLETT2_CONFIG_SET_NO_MIXER) + return 0; + + /* Add standalone control */ + return scarlett2_add_new_ctl(mixer, &scarlett2_standalone_ctl, + 0, 1, "Standalone Switch", NULL); +} + /*** Cleanup/Suspend Callbacks ***/ static void scarlett2_private_free(struct usb_mixer_interface *mixer) @@ -3632,9 +3732,15 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) return err; /* the rest of the configuration is for devices with a mixer */ - if (!info->has_mixer) + if (info->config_set == SCARLETT2_CONFIG_SET_NO_MIXER) return 0; + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_STANDALONE_SWITCH, + 1, &private->standalone_switch); + if (err < 0) + return err; + err = scarlett2_update_sync(mixer); if (err < 0) return err; @@ -3957,6 +4063,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer) if (err < 0) return err; + /* Create the standalone control */ + err = scarlett2_add_standalone_ctl(mixer); + if (err < 0) + return err; + /* Set up the interrupt polling */ err = scarlett2_init_notify(mixer); if (err < 0) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 4a3ff6468aa7..b00634663346 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1254,18 +1254,6 @@ static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream) } /* - * ALSA PCM mmap callback - */ -static int had_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - return remap_pfn_range(vma, vma->vm_start, - substream->runtime->dma_addr >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); -} - -/* * ALSA PCM ops */ static const struct snd_pcm_ops had_pcm_ops = { @@ -1276,7 +1264,6 @@ static const struct snd_pcm_ops had_pcm_ops = { .trigger = had_pcm_trigger, .sync_stop = had_pcm_sync_stop, .pointer = had_pcm_pointer, - .mmap = had_pcm_mmap, }; /* process mode change of the running stream; called in mutex */ |