Merge tag 'asoc-fix-v6.9-merge-window' of https://git.kernel.org/pub/scm/linux/kernel...
authorTakashi Iwai <tiwai@suse.de>
Thu, 21 Mar 2024 13:07:27 +0000 (14:07 +0100)
committerTakashi Iwai <tiwai@suse.de>
Thu, 21 Mar 2024 13:07:27 +0000 (14:07 +0100)
ASoC: Fixes for v6.9

A bunch of fixes that came in during the merge window, probably the most
substantial thing is the DPCM locking fix for compressed audio which has
been lurking for a while.

135 files changed:
Documentation/sound/kernel-api/writing-an-alsa-driver.rst
MAINTAINERS
drivers/acpi/scan.c
drivers/platform/x86/serial-multi-instantiate.c
include/sound/ak4531_codec.h
include/sound/cs35l56.h
include/sound/emux_synth.h
include/sound/pcm.h
include/sound/sb.h
include/uapi/linux/virtio_snd.h
sound/aoa/fabrics/layout.c
sound/aoa/soundbus/core.c
sound/arm/aaci.c
sound/arm/pxa2xx-ac97.c
sound/core/.kunitconfig [new file with mode: 0644]
sound/core/Kconfig
sound/core/Makefile
sound/core/compress_offload.c
sound/core/control.c
sound/core/control_compat.c
sound/core/control_led.c
sound/core/hrtimer.c
sound/core/hwdep.c
sound/core/info.c
sound/core/info_oss.c
sound/core/init.c
sound/core/jack.c
sound/core/oss/mixer_oss.c
sound/core/oss/pcm_oss.c
sound/core/pcm.c
sound/core/pcm_compat.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/seq/Kconfig
sound/core/seq/oss/seq_oss_device.h
sound/core/seq/oss/seq_oss_init.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/seq_compat.c
sound/core/seq/seq_fifo.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_midi_event.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_prioq.c
sound/core/seq/seq_queue.c
sound/core/seq/seq_timer.c
sound/core/seq/seq_ump_client.c
sound/core/seq/seq_virmidi.c
sound/core/seq_device.c
sound/core/sound.c
sound/core/sound_kunit.c [new file with mode: 0644]
sound/core/sound_oss.c
sound/core/timer.c
sound/core/timer_compat.c
sound/core/ump.c
sound/core/vmaster.c
sound/drivers/aloop.c
sound/drivers/dummy.c
sound/drivers/pcsp/pcsp.c
sound/firewire/Kconfig
sound/firewire/amdtp-stream.c
sound/firewire/amdtp-stream.h
sound/firewire/motu/motu-protocol-v3.c
sound/firewire/motu/motu.c
sound/firewire/motu/motu.h
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/oxfw/oxfw.c
sound/firewire/oxfw/oxfw.h
sound/hda/hdac_i915.c
sound/hda/hdac_stream.c
sound/hda/intel-sdw-acpi.c
sound/pci/ac97/ac97_patch.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/aw2/aw2-saa7146.h
sound/pci/azt3328.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/ctxfi/ctamixer.c
sound/pci/ctxfi/ctamixer.h
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctdaio.c
sound/pci/ctxfi/ctdaio.h
sound/pci/ctxfi/ctsrc.c
sound/pci/ctxfi/ctsrc.h
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/echoaudio.h
sound/pci/echoaudio/echoaudio_3g.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/cs35l41_hda_property.c
sound/pci/hda/cs35l56_hda.c
sound/pci/hda/cs35l56_hda.h
sound/pci/hda/cs35l56_hda_i2c.c
sound/pci/hda/cs35l56_hda_spi.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_beep.h
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_component.c [new file with mode: 0644]
sound/pci/hda/hda_component.h
sound/pci/hda/hda_controller.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/tas2781_hda_i2c.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/maestro3.c
sound/pci/nm256/nm256.c
sound/pci/riptide/riptide.c
sound/pci/rme96.c
sound/pci/sis7019.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/soc/codecs/cs35l56-sdw.c
sound/soc/codecs/cs35l56-shared.c
sound/soc/codecs/cs35l56.c
sound/soc/codecs/hda.c
sound/soc/intel/avs/core.c
sound/soc/pxa/pxa2xx-ac97.c
sound/spi/at73c213.c
sound/synth/emux/emux.c
sound/usb/mixer_scarlett2.c
sound/usb/stream.c
sound/virtio/Makefile
sound/virtio/virtio_card.c
sound/virtio/virtio_card.h
sound/virtio/virtio_kctl.c [new file with mode: 0644]

index cd421856409e6579d788fc5089027ed7c2c77915..2d2998faff62b9e7809168cb7a5b94f6a3f03b08 100644 (file)
@@ -3864,14 +3864,16 @@ corresponding destructor.
 
 And next, set suspend/resume callbacks to the pci_driver::
 
-  static SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
+  static DEFINE_SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
 
   static struct pci_driver driver = {
           .name = KBUILD_MODNAME,
           .id_table = snd_my_ids,
           .probe = snd_my_probe,
           .remove = snd_my_remove,
-          .driver.pm = &snd_my_pm_ops,
+          .driver = {
+                  .pm = &snd_my_pm_ops,
+          },
   };
 
 Module Parameters
index 1aabf1c15bb30390f6286a291afdee9c93307ada..6f589aee6146354dd9a044e3e044814af35022b2 100644 (file)
@@ -5015,6 +5015,7 @@ F:        include/linux/mfd/cs42l43*
 F:     include/sound/cs*
 F:     sound/pci/hda/cirrus*
 F:     sound/pci/hda/cs*
+F:     sound/pci/hda/hda_component*
 F:     sound/pci/hda/hda_cs_dsp_ctl.*
 F:     sound/soc/codecs/cs*
 
@@ -20488,6 +20489,12 @@ F:     include/uapi/sound/compress_*
 F:     sound/core/compress_offload.c
 F:     sound/soc/soc-compress.c
 
+SOUND - CORE KUNIT TEST
+M:     Ivan Orlov <ivan.orlov0322@gmail.com>
+L:     linux-sound@vger.kernel.org
+S:     Supported
+F:     sound/core/sound_kunit.c
+
 SOUND - DMAENGINE HELPERS
 M:     Lars-Peter Clausen <lars@metafoo.de>
 S:     Supported
index e6ed1ba91e5c9152c7eeec242c302f91fda42d5d..091c501bed1fe3aafb928511476b442098e65778 100644 (file)
@@ -1725,7 +1725,9 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
                {"BSG1160", },
                {"BSG2150", },
                {"CSC3551", },
+               {"CSC3554", },
                {"CSC3556", },
+               {"CSC3557", },
                {"INT33FE", },
                {"INT3515", },
                /* Non-conforming _HID for Cirrus Logic already released */
index 8158e3cf5d6dec12903c1b8b97f682da451f5df3..97b9c63922303af20175d15ca76dcb93e8e91601 100644 (file)
@@ -329,6 +329,19 @@ static const struct smi_node cs35l41_hda = {
        .bus_type = SMI_AUTO_DETECT,
 };
 
+static const struct smi_node cs35l54_hda = {
+       .instances = {
+               { "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
+               /* a 5th entry is an alias address, not a real device */
+               { "cs35l54-hda_dummy_dev" },
+               {}
+       },
+       .bus_type = SMI_AUTO_DETECT,
+};
+
 static const struct smi_node cs35l56_hda = {
        .instances = {
                { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
@@ -342,6 +355,19 @@ static const struct smi_node cs35l56_hda = {
        .bus_type = SMI_AUTO_DETECT,
 };
 
+static const struct smi_node cs35l57_hda = {
+       .instances = {
+               { "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
+               /* a 5th entry is an alias address, not a real device */
+               { "cs35l57-hda_dummy_dev" },
+               {}
+       },
+       .bus_type = SMI_AUTO_DETECT,
+};
+
 /*
  * Note new device-ids must also be added to ignore_serial_bus_ids in
  * drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
@@ -350,7 +376,9 @@ static const struct acpi_device_id smi_acpi_ids[] = {
        { "BSG1160", (unsigned long)&bsg1160_data },
        { "BSG2150", (unsigned long)&bsg2150_data },
        { "CSC3551", (unsigned long)&cs35l41_hda },
+       { "CSC3554", (unsigned long)&cs35l54_hda },
        { "CSC3556", (unsigned long)&cs35l56_hda },
+       { "CSC3557", (unsigned long)&cs35l57_hda },
        { "INT3515", (unsigned long)&int3515_data },
        /* Non-conforming _HID for Cirrus Logic already released */
        { "CLSA0100", (unsigned long)&cs35l41_hda },
index 9a4429970d929eab60e622b9fc3a6cae4cd2ccb3..64402347d7a253dec5e0bef5379bc5480a14d0e2 100644 (file)
@@ -65,6 +65,9 @@ int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531,
 #ifdef CONFIG_PM
 void snd_ak4531_suspend(struct snd_ak4531 *ak4531);
 void snd_ak4531_resume(struct snd_ak4531 *ak4531);
+#else
+static inline void snd_ak4531_suspend(struct snd_ak4531 *ak4531) {}
+static inline void snd_ak4531_resume(struct snd_ak4531 *ak4531) {}
 #endif
 
 #endif /* __SOUND_AK4531_CODEC_H */
index 4014ed7097b30815ba999d99cbfea024fc1528b4..e0629699b56338a76b69616dcc2a79dece2e51f4 100644 (file)
@@ -261,6 +261,7 @@ struct cs35l56_base {
        struct regmap *regmap;
        int irq;
        struct mutex irq_lock;
+       u8 type;
        u8 rev;
        bool init_done;
        bool fw_patched;
index 1cc530434b97b4bc1a9996e216f826d1b663dc00..3f7f365ed248cd82c0fd96c0414ccfdc2c4079ae 100644 (file)
@@ -103,7 +103,7 @@ struct snd_emux {
        int ports[SNDRV_EMUX_MAX_PORTS];        /* The ports for this device */
        struct snd_emux_port *portptrs[SNDRV_EMUX_MAX_PORTS];
        int used;       /* use counter */
-       char *name;     /* name of the device (internal) */
+       const char *name;       /* name of the device (internal) */
        struct snd_rawmidi **vmidi;
        struct timer_list tlist;        /* for pending note-offs */
        int timer_active;
index cc175c623dac71d63062beb2441f5b94ec35d346..210096f124eed5765960b2b512954fb3dfa5c4ec 100644 (file)
@@ -659,6 +659,18 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
                flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
        } while (0)
 
+/* definitions for guard(); use like guard(pcm_stream_lock) */
+DEFINE_LOCK_GUARD_1(pcm_stream_lock, struct snd_pcm_substream,
+                   snd_pcm_stream_lock(_T->lock),
+                   snd_pcm_stream_unlock(_T->lock))
+DEFINE_LOCK_GUARD_1(pcm_stream_lock_irq, struct snd_pcm_substream,
+                   snd_pcm_stream_lock_irq(_T->lock),
+                   snd_pcm_stream_unlock_irq(_T->lock))
+DEFINE_LOCK_GUARD_1(pcm_stream_lock_irqsave, struct snd_pcm_substream,
+                   snd_pcm_stream_lock_irqsave(_T->lock, _T->flags),
+                   snd_pcm_stream_unlock_irqrestore(_T->lock, _T->flags),
+                   unsigned long flags)
+
 /**
  * snd_pcm_group_for_each_entry - iterate over the linked substreams
  * @s: the iterator
index f540339fb0c77497d618482601972672d4b48913..24970f36c38ae9f6eda2bd0a6353a70abaaf4760 100644 (file)
@@ -290,6 +290,9 @@ int snd_sbmixer_new(struct snd_sb *chip);
 #ifdef CONFIG_PM
 void snd_sbmixer_suspend(struct snd_sb *chip);
 void snd_sbmixer_resume(struct snd_sb *chip);
+#else
+static inline void snd_sbmixer_suspend(struct snd_sb *chip) {}
+static inline void snd_sbmixer_resume(struct snd_sb *chip) {}
 #endif
 
 /* sb8_init.c */
index dfe49547a7b04d6aa7e9cb474a0f103b2cd2b043..5f4100c2cf04cb44494fec115b70095f530b42c2 100644 (file)
@@ -7,6 +7,14 @@
 
 #include <linux/virtio_types.h>
 
+/*******************************************************************************
+ * FEATURE BITS
+ */
+enum {
+       /* device supports control elements */
+       VIRTIO_SND_F_CTLS = 0
+};
+
 /*******************************************************************************
  * CONFIGURATION SPACE
  */
@@ -17,6 +25,8 @@ struct virtio_snd_config {
        __le32 streams;
        /* # of available channel maps */
        __le32 chmaps;
+       /* # of available control elements */
+       __le32 controls;
 };
 
 enum {
@@ -55,6 +65,15 @@ enum {
        /* channel map control request types */
        VIRTIO_SND_R_CHMAP_INFO = 0x0200,
 
+       /* control element request types */
+       VIRTIO_SND_R_CTL_INFO = 0x0300,
+       VIRTIO_SND_R_CTL_ENUM_ITEMS,
+       VIRTIO_SND_R_CTL_READ,
+       VIRTIO_SND_R_CTL_WRITE,
+       VIRTIO_SND_R_CTL_TLV_READ,
+       VIRTIO_SND_R_CTL_TLV_WRITE,
+       VIRTIO_SND_R_CTL_TLV_COMMAND,
+
        /* jack event types */
        VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
        VIRTIO_SND_EVT_JACK_DISCONNECTED,
@@ -63,6 +82,9 @@ enum {
        VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
        VIRTIO_SND_EVT_PCM_XRUN,
 
+       /* control element event types */
+       VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200,
+
        /* common status codes */
        VIRTIO_SND_S_OK = 0x8000,
        VIRTIO_SND_S_BAD_MSG,
@@ -331,4 +353,136 @@ struct virtio_snd_chmap_info {
        __u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE];
 };
 
+/*******************************************************************************
+ * CONTROL ELEMENTS MESSAGES
+ */
+struct virtio_snd_ctl_hdr {
+       /* VIRTIO_SND_R_CTL_XXX */
+       struct virtio_snd_hdr hdr;
+       /* 0 ... virtio_snd_config::controls - 1 */
+       __le32 control_id;
+};
+
+/* supported roles for control elements */
+enum {
+       VIRTIO_SND_CTL_ROLE_UNDEFINED = 0,
+       VIRTIO_SND_CTL_ROLE_VOLUME,
+       VIRTIO_SND_CTL_ROLE_MUTE,
+       VIRTIO_SND_CTL_ROLE_GAIN
+};
+
+/* supported value types for control elements */
+enum {
+       VIRTIO_SND_CTL_TYPE_BOOLEAN = 0,
+       VIRTIO_SND_CTL_TYPE_INTEGER,
+       VIRTIO_SND_CTL_TYPE_INTEGER64,
+       VIRTIO_SND_CTL_TYPE_ENUMERATED,
+       VIRTIO_SND_CTL_TYPE_BYTES,
+       VIRTIO_SND_CTL_TYPE_IEC958
+};
+
+/* supported access rights for control elements */
+enum {
+       VIRTIO_SND_CTL_ACCESS_READ = 0,
+       VIRTIO_SND_CTL_ACCESS_WRITE,
+       VIRTIO_SND_CTL_ACCESS_VOLATILE,
+       VIRTIO_SND_CTL_ACCESS_INACTIVE,
+       VIRTIO_SND_CTL_ACCESS_TLV_READ,
+       VIRTIO_SND_CTL_ACCESS_TLV_WRITE,
+       VIRTIO_SND_CTL_ACCESS_TLV_COMMAND
+};
+
+struct virtio_snd_ctl_info {
+       /* common header */
+       struct virtio_snd_info hdr;
+       /* element role (VIRTIO_SND_CTL_ROLE_XXX) */
+       __le32 role;
+       /* element value type (VIRTIO_SND_CTL_TYPE_XXX) */
+       __le32 type;
+       /* element access right bit map (1 << VIRTIO_SND_CTL_ACCESS_XXX) */
+       __le32 access;
+       /* # of members in the element value */
+       __le32 count;
+       /* index for an element with a non-unique name */
+       __le32 index;
+       /* name identifier string for the element */
+       __u8 name[44];
+       /* additional information about the element's value */
+       union {
+               /* VIRTIO_SND_CTL_TYPE_INTEGER */
+               struct {
+                       /* minimum supported value */
+                       __le32 min;
+                       /* maximum supported value */
+                       __le32 max;
+                       /* fixed step size for value (0 = variable size) */
+                       __le32 step;
+               } integer;
+               /* VIRTIO_SND_CTL_TYPE_INTEGER64 */
+               struct {
+                       /* minimum supported value */
+                       __le64 min;
+                       /* maximum supported value */
+                       __le64 max;
+                       /* fixed step size for value (0 = variable size) */
+                       __le64 step;
+               } integer64;
+               /* VIRTIO_SND_CTL_TYPE_ENUMERATED */
+               struct {
+                       /* # of options supported for value */
+                       __le32 items;
+               } enumerated;
+       } value;
+};
+
+struct virtio_snd_ctl_enum_item {
+       /* option name */
+       __u8 item[64];
+};
+
+struct virtio_snd_ctl_iec958 {
+       /* AES/IEC958 channel status bits */
+       __u8 status[24];
+       /* AES/IEC958 subcode bits */
+       __u8 subcode[147];
+       /* nothing */
+       __u8 pad;
+       /* AES/IEC958 subframe bits */
+       __u8 dig_subframe[4];
+};
+
+struct virtio_snd_ctl_value {
+       union {
+               /* VIRTIO_SND_CTL_TYPE_BOOLEAN|INTEGER value */
+               __le32 integer[128];
+               /* VIRTIO_SND_CTL_TYPE_INTEGER64 value */
+               __le64 integer64[64];
+               /* VIRTIO_SND_CTL_TYPE_ENUMERATED value (option indexes) */
+               __le32 enumerated[128];
+               /* VIRTIO_SND_CTL_TYPE_BYTES value */
+               __u8 bytes[512];
+               /* VIRTIO_SND_CTL_TYPE_IEC958 value */
+               struct virtio_snd_ctl_iec958 iec958;
+       } value;
+};
+
+/* supported event reason types */
+enum {
+       /* element's value has changed */
+       VIRTIO_SND_CTL_EVT_MASK_VALUE = 0,
+       /* element's information has changed */
+       VIRTIO_SND_CTL_EVT_MASK_INFO,
+       /* element's metadata has changed */
+       VIRTIO_SND_CTL_EVT_MASK_TLV
+};
+
+struct virtio_snd_ctl_event {
+       /* VIRTIO_SND_EVT_CTL_NOTIFY */
+       struct virtio_snd_hdr hdr;
+       /* 0 ... virtio_snd_config::controls - 1 */
+       __le16 control_id;
+       /* event reason bit map (1 << VIRTIO_SND_CTL_EVT_MASK_XXX) */
+       __le16 mask;
+};
+
 #endif /* VIRTIO_SND_IF_H */
index 0cd19a05db1987e222548dbb95b3bf76b71a586e..e68b4cb4df296aa2d01929a32cc765ede53ef879 100644 (file)
@@ -1126,7 +1126,6 @@ static void aoa_fabric_layout_remove(struct soundbus_dev *sdev)
        sdev->pcmname = NULL;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int aoa_fabric_layout_suspend(struct device *dev)
 {
        struct layout_dev *ldev = dev_get_drvdata(dev);
@@ -1147,11 +1146,9 @@ static int aoa_fabric_layout_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
        aoa_fabric_layout_suspend, aoa_fabric_layout_resume);
 
-#endif
-
 static struct soundbus_driver aoa_soundbus_driver = {
        .name = "snd_aoa_soundbus_drv",
        .owner = THIS_MODULE,
@@ -1159,9 +1156,7 @@ static struct soundbus_driver aoa_soundbus_driver = {
        .remove = aoa_fabric_layout_remove,
        .driver = {
                .owner = THIS_MODULE,
-#ifdef CONFIG_PM_SLEEP
                .pm = &aoa_fabric_layout_pm_ops,
-#endif
        }
 };
 
index 8f24a3eea16bd34f8c890248538749758fab0cb7..2a295f6105942813b9541b9c0a287218c7e6b3a9 100644 (file)
@@ -127,7 +127,7 @@ static void soundbus_device_shutdown(struct device *dev)
 
 /* soundbus_dev_attrs is declared in sysfs.c */
 ATTRIBUTE_GROUPS(soundbus_dev);
-static struct bus_type soundbus_bus_type = {
+static const struct bus_type soundbus_bus_type = {
        .name           = "aoa-soundbus",
        .probe          = soundbus_probe,
        .uevent         = soundbus_uevent,
index 0817ad21af74f4b0e19ac77e60b2a06b488a808e..c3340b8ff3dafe683416f5e34ce122206543b97d 100644 (file)
@@ -737,10 +737,8 @@ static const struct snd_pcm_ops aaci_capture_ops = {
 /*
  * Power Management.
  */
-#ifdef CONFIG_PM
 static int aaci_do_suspend(struct snd_card *card)
 {
-       struct aaci *aaci = card->private_data;
        snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
        return 0;
 }
@@ -763,12 +761,7 @@ static int aaci_resume(struct device *dev)
        return card ? aaci_do_resume(card) : 0;
 }
 
-static SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
-#define AACI_DEV_PM_OPS (&aaci_dev_pm_ops)
-#else
-#define AACI_DEV_PM_OPS NULL
-#endif
-
+static DEFINE_SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
 
 static const struct ac97_pcm ac97_defs[] = {
        [0] = { /* Front PCM */
@@ -1081,7 +1074,7 @@ MODULE_DEVICE_TABLE(amba, aaci_ids);
 static struct amba_driver aaci_driver = {
        .drv            = {
                .name   = DRIVER_NAME,
-               .pm     = AACI_DEV_PM_OPS,
+               .pm     = &aaci_dev_pm_ops,
        },
        .probe          = aaci_probe,
        .remove         = aaci_remove,
index 2d83ad91f96800538fe0b4aea9e16d4274d0b03d..4c367e73b2c9b3e35d7a4623935c8266cd92a203 100644 (file)
@@ -111,8 +111,6 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
        return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
 }
 
-#ifdef CONFIG_PM_SLEEP
-
 static int pxa2xx_ac97_do_suspend(struct snd_card *card)
 {
        pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
@@ -164,8 +162,7 @@ static int pxa2xx_ac97_resume(struct device *dev)
        return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
 
 static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
        .open           = pxa2xx_ac97_pcm_open,
@@ -277,9 +274,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
        .remove_new     = pxa2xx_ac97_remove,
        .driver         = {
                .name   = "pxa2xx-ac97",
-#ifdef CONFIG_PM_SLEEP
                .pm     = &pxa2xx_ac97_pm_ops,
-#endif
        },
 };
 
diff --git a/sound/core/.kunitconfig b/sound/core/.kunitconfig
new file mode 100644 (file)
index 0000000..440f974
--- /dev/null
@@ -0,0 +1,5 @@
+CONFIG_KUNIT=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_PCM=y
+CONFIG_SND_CORE_TEST=y
index e41818e59a1585e1bd164e094118e0e9d5ffce2c..8077f481d84fd6baf3be305b2b6936575d937a3a 100644 (file)
@@ -39,6 +39,23 @@ config SND_UMP_LEGACY_RAWMIDI
          legacy MIDI 1.0 byte streams is created for each UMP Endpoint.
          The device contains 16 substreams corresponding to UMP groups.
 
+config SND_CORE_TEST
+       tristate "Sound core KUnit test"
+       depends on KUNIT
+       select SND_PCM
+       default KUNIT_ALL_TESTS
+       help
+         This options enables the sound core functions KUnit test.
+
+         KUnit tests run during boot and output the results to the debug
+         log in TAP format (https://testanything.org/). Only useful for
+         kernel devs running KUnit test harness and are not for inclusion
+         into a production build.
+
+         For more information on KUnit and unit tests in general, refer
+         to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+
 config SND_COMPRESS_OFFLOAD
        tristate
 
index f6526b33713756071c14d4da2c7e051d1ae17bf9..b8aa886198ab084d38ca2fefca8afe88154752c3 100644 (file)
@@ -48,6 +48,8 @@ obj-$(CONFIG_SND_SEQ_DEVICE)  += snd-seq-device.o
 obj-$(CONFIG_SND_RAWMIDI)      += snd-rawmidi.o
 obj-$(CONFIG_SND_UMP)          += snd-ump.o
 
+obj-$(CONFIG_SND_CORE_TEST)    += sound_kunit.o
+
 obj-$(CONFIG_SND_OSSEMUL)      += oss/
 obj-$(CONFIG_SND_SEQUENCER)    += seq/
 
index 619371aa9964dcb23f24bbae1658fb891b11ca20..f0008fa2d8396c8e898829a41360dc11eed19b1d 100644 (file)
@@ -127,9 +127,8 @@ static int snd_compr_open(struct inode *inode, struct file *f)
        init_waitqueue_head(&runtime->sleep);
        data->stream.runtime = runtime;
        f->private_data = (void *)data;
-       mutex_lock(&compr->lock);
-       ret = compr->ops->open(&data->stream);
-       mutex_unlock(&compr->lock);
+       scoped_guard(mutex, &compr->lock)
+               ret = compr->ops->open(&data->stream);
        if (ret) {
                kfree(runtime);
                kfree(data);
@@ -288,7 +287,7 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
                return -EFAULT;
 
        stream = &data->stream;
-       mutex_lock(&stream->device->lock);
+       guard(mutex)(&stream->device->lock);
        /* write is allowed when stream is running or has been steup */
        switch (stream->runtime->state) {
        case SNDRV_PCM_STATE_SETUP:
@@ -296,7 +295,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
        case SNDRV_PCM_STATE_RUNNING:
                break;
        default:
-               mutex_unlock(&stream->device->lock);
                return -EBADFD;
        }
 
@@ -322,7 +320,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
                pr_debug("stream prepared, Houston we are good to go\n");
        }
 
-       mutex_unlock(&stream->device->lock);
        return retval;
 }
 
@@ -339,7 +336,7 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
                return -EFAULT;
 
        stream = &data->stream;
-       mutex_lock(&stream->device->lock);
+       guard(mutex)(&stream->device->lock);
 
        /* read is allowed when stream is running, paused, draining and setup
         * (yes setup is state which we transition to after stop, so if user
@@ -350,11 +347,9 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
        case SNDRV_PCM_STATE_PREPARED:
        case SNDRV_PCM_STATE_SUSPENDED:
        case SNDRV_PCM_STATE_DISCONNECTED:
-               retval = -EBADFD;
-               goto out;
+               return -EBADFD;
        case SNDRV_PCM_STATE_XRUN:
-               retval = -EPIPE;
-               goto out;
+               return -EPIPE;
        }
 
        avail = snd_compr_get_avail(stream);
@@ -363,17 +358,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
        if (avail > count)
                avail = count;
 
-       if (stream->ops->copy) {
+       if (stream->ops->copy)
                retval = stream->ops->copy(stream, buf, avail);
-       } else {
-               retval = -ENXIO;
-               goto out;
-       }
+       else
+               return -ENXIO;
        if (retval > 0)
                stream->runtime->total_bytes_transferred += retval;
 
-out:
-       mutex_unlock(&stream->device->lock);
        return retval;
 }
 
@@ -402,13 +393,12 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
 
        stream = &data->stream;
 
-       mutex_lock(&stream->device->lock);
+       guard(mutex)(&stream->device->lock);
 
        switch (stream->runtime->state) {
        case SNDRV_PCM_STATE_OPEN:
        case SNDRV_PCM_STATE_XRUN:
-               retval = snd_compr_get_poll(stream) | EPOLLERR;
-               goto out;
+               return snd_compr_get_poll(stream) | EPOLLERR;
        default:
                break;
        }
@@ -433,11 +423,9 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
                        retval = snd_compr_get_poll(stream);
                break;
        default:
-               retval = snd_compr_get_poll(stream) | EPOLLERR;
-               break;
+               return snd_compr_get_poll(stream) | EPOLLERR;
        }
-out:
-       mutex_unlock(&stream->device->lock);
+
        return retval;
 }
 
@@ -465,7 +453,7 @@ static int
 snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
 {
        int retval;
-       struct snd_compr_codec_caps *caps;
+       struct snd_compr_codec_caps *caps __free(kfree) = NULL;
 
        if (!stream->ops->get_codec_caps)
                return -ENXIO;
@@ -476,12 +464,9 @@ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
 
        retval = stream->ops->get_codec_caps(stream, caps);
        if (retval)
-               goto out;
+               return retval;
        if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
-               retval = -EFAULT;
-
-out:
-       kfree(caps);
+               return -EFAULT;
        return retval;
 }
 #endif /* !COMPR_CODEC_CAPS_OVERFLOW */
@@ -586,7 +571,7 @@ static int snd_compress_check_input(struct snd_compr_params *params)
 static int
 snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
 {
-       struct snd_compr_params *params;
+       struct snd_compr_params *params __free(kfree) = NULL;
        int retval;
 
        if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) {
@@ -596,24 +581,22 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
                 */
                params = memdup_user((void __user *)arg, sizeof(*params));
                if (IS_ERR(params))
-                       return PTR_ERR(params);
+                       return PTR_ERR(no_free_ptr(params));
 
                retval = snd_compress_check_input(params);
                if (retval)
-                       goto out;
+                       return retval;
 
                retval = snd_compr_allocate_buffer(stream, params);
-               if (retval) {
-                       retval = -ENOMEM;
-                       goto out;
-               }
+               if (retval)
+                       return -ENOMEM;
 
                retval = stream->ops->set_params(stream, params);
                if (retval)
-                       goto out;
+                       return retval;
 
                if (stream->next_track)
-                       goto out;
+                       return retval;
 
                stream->metadata_set = false;
                stream->next_track = false;
@@ -622,15 +605,13 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
        } else {
                return -EPERM;
        }
-out:
-       kfree(params);
        return retval;
 }
 
 static int
 snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
 {
-       struct snd_codec *params;
+       struct snd_codec *params __free(kfree) = NULL;
        int retval;
 
        if (!stream->ops->get_params)
@@ -641,12 +622,9 @@ snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
                return -ENOMEM;
        retval = stream->ops->get_params(stream, params);
        if (retval)
-               goto out;
+               return retval;
        if (copy_to_user((char __user *)arg, params, sizeof(*params)))
-               retval = -EFAULT;
-
-out:
-       kfree(params);
+               return -EFAULT;
        return retval;
 }
 
@@ -805,12 +783,10 @@ static void error_delayed_work(struct work_struct *work)
 
        stream = container_of(work, struct snd_compr_stream, error_work.work);
 
-       mutex_lock(&stream->device->lock);
+       guard(mutex)(&stream->device->lock);
 
        stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
        wake_up(&stream->runtime->sleep);
-
-       mutex_unlock(&stream->device->lock);
 }
 
 /**
@@ -967,70 +943,52 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 {
        struct snd_compr_file *data = f->private_data;
        struct snd_compr_stream *stream;
-       int retval = -ENOTTY;
 
        if (snd_BUG_ON(!data))
                return -EFAULT;
 
        stream = &data->stream;
 
-       mutex_lock(&stream->device->lock);
+       guard(mutex)(&stream->device->lock);
        switch (_IOC_NR(cmd)) {
        case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
-               retval = put_user(SNDRV_COMPRESS_VERSION,
+               return put_user(SNDRV_COMPRESS_VERSION,
                                (int __user *)arg) ? -EFAULT : 0;
-               break;
        case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
-               retval = snd_compr_get_caps(stream, arg);
-               break;
+               return snd_compr_get_caps(stream, arg);
 #ifndef COMPR_CODEC_CAPS_OVERFLOW
        case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
-               retval = snd_compr_get_codec_caps(stream, arg);
-               break;
+               return snd_compr_get_codec_caps(stream, arg);
 #endif
        case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
-               retval = snd_compr_set_params(stream, arg);
-               break;
+               return snd_compr_set_params(stream, arg);
        case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
-               retval = snd_compr_get_params(stream, arg);
-               break;
+               return snd_compr_get_params(stream, arg);
        case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
-               retval = snd_compr_set_metadata(stream, arg);
-               break;
+               return snd_compr_set_metadata(stream, arg);
        case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
-               retval = snd_compr_get_metadata(stream, arg);
-               break;
+               return snd_compr_get_metadata(stream, arg);
        case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
-               retval = snd_compr_tstamp(stream, arg);
-               break;
+               return snd_compr_tstamp(stream, arg);
        case _IOC_NR(SNDRV_COMPRESS_AVAIL):
-               retval = snd_compr_ioctl_avail(stream, arg);
-               break;
+               return snd_compr_ioctl_avail(stream, arg);
        case _IOC_NR(SNDRV_COMPRESS_PAUSE):
-               retval = snd_compr_pause(stream);
-               break;
+               return snd_compr_pause(stream);
        case _IOC_NR(SNDRV_COMPRESS_RESUME):
-               retval = snd_compr_resume(stream);
-               break;
+               return snd_compr_resume(stream);
        case _IOC_NR(SNDRV_COMPRESS_START):
-               retval = snd_compr_start(stream);
-               break;
+               return snd_compr_start(stream);
        case _IOC_NR(SNDRV_COMPRESS_STOP):
-               retval = snd_compr_stop(stream);
-               break;
+               return snd_compr_stop(stream);
        case _IOC_NR(SNDRV_COMPRESS_DRAIN):
-               retval = snd_compr_drain(stream);
-               break;
+               return snd_compr_drain(stream);
        case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
-               retval = snd_compr_partial_drain(stream);
-               break;
+               return snd_compr_partial_drain(stream);
        case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
-               retval = snd_compr_next_track(stream);
-               break;
-
+               return snd_compr_next_track(stream);
        }
-       mutex_unlock(&stream->device->lock);
-       return retval;
+
+       return -ENOTTY;
 }
 
 /* support of 32bit userspace on 64bit platforms */
index 59c8658966d4cb37cc571c4d21da8c2dc57a4ee7..fb0c60044f7b3b1a4a8fd478cf68306a9443ef5d 100644 (file)
@@ -44,7 +44,6 @@ static int snd_ctl_remove_locked(struct snd_card *card,
 
 static int snd_ctl_open(struct inode *inode, struct file *file)
 {
-       unsigned long flags;
        struct snd_card *card;
        struct snd_ctl_file *ctl;
        int i, err;
@@ -80,9 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
                ctl->preferred_subdevice[i] = -1;
        ctl->pid = get_pid(task_pid(current));
        file->private_data = ctl;
-       write_lock_irqsave(&card->ctl_files_rwlock, flags);
-       list_add_tail(&ctl->list, &card->ctl_files);
-       write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
+       scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock)
+               list_add_tail(&ctl->list, &card->ctl_files);
        snd_card_unref(card);
        return 0;
 
@@ -98,21 +96,18 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
 
 static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
 {
-       unsigned long flags;
        struct snd_kctl_event *cread;
 
-       spin_lock_irqsave(&ctl->read_lock, flags);
+       guard(spinlock_irqsave)(&ctl->read_lock);
        while (!list_empty(&ctl->events)) {
                cread = snd_kctl_event(ctl->events.next);
                list_del(&cread->list);
                kfree(cread);
        }
-       spin_unlock_irqrestore(&ctl->read_lock, flags);
 }
 
 static int snd_ctl_release(struct inode *inode, struct file *file)
 {
-       unsigned long flags;
        struct snd_card *card;
        struct snd_ctl_file *ctl;
        struct snd_kcontrol *control;
@@ -121,15 +116,17 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
        ctl = file->private_data;
        file->private_data = NULL;
        card = ctl->card;
-       write_lock_irqsave(&card->ctl_files_rwlock, flags);
-       list_del(&ctl->list);
-       write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
-       down_write(&card->controls_rwsem);
-       list_for_each_entry(control, &card->controls, list)
-               for (idx = 0; idx < control->count; idx++)
-                       if (control->vd[idx].owner == ctl)
-                               control->vd[idx].owner = NULL;
-       up_write(&card->controls_rwsem);
+
+       scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock)
+               list_del(&ctl->list);
+
+       scoped_guard(rwsem_write, &card->controls_rwsem) {
+               list_for_each_entry(control, &card->controls, list)
+                       for (idx = 0; idx < control->count; idx++)
+                               if (control->vd[idx].owner == ctl)
+                                       control->vd[idx].owner = NULL;
+       }
+
        snd_fasync_free(ctl->fasync);
        snd_ctl_empty_read_queue(ctl);
        put_pid(ctl->pid);
@@ -152,7 +149,6 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
 void snd_ctl_notify(struct snd_card *card, unsigned int mask,
                    struct snd_ctl_elem_id *id)
 {
-       unsigned long flags;
        struct snd_ctl_file *ctl;
        struct snd_kctl_event *ev;
 
@@ -160,34 +156,34 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
                return;
        if (card->shutdown)
                return;
-       read_lock_irqsave(&card->ctl_files_rwlock, flags);
+
+       guard(read_lock_irqsave)(&card->ctl_files_rwlock);
 #if IS_ENABLED(CONFIG_SND_MIXER_OSS)
        card->mixer_oss_change_count++;
 #endif
        list_for_each_entry(ctl, &card->ctl_files, list) {
                if (!ctl->subscribed)
                        continue;
-               spin_lock(&ctl->read_lock);
-               list_for_each_entry(ev, &ctl->events, list) {
-                       if (ev->id.numid == id->numid) {
-                               ev->mask |= mask;
-                               goto _found;
+               scoped_guard(spinlock, &ctl->read_lock) {
+                       list_for_each_entry(ev, &ctl->events, list) {
+                               if (ev->id.numid == id->numid) {
+                                       ev->mask |= mask;
+                                       goto _found;
+                               }
                        }
+                       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+                       if (ev) {
+                               ev->id = *id;
+                               ev->mask = mask;
+                               list_add_tail(&ev->list, &ctl->events);
+                       } else {
+                               dev_err(card->dev, "No memory available to allocate event\n");
+                       }
+_found:
+                       wake_up(&ctl->change_sleep);
                }
-               ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-               if (ev) {
-                       ev->id = *id;
-                       ev->mask = mask;
-                       list_add_tail(&ev->list, &ctl->events);
-               } else {
-                       dev_err(card->dev, "No memory available to allocate event\n");
-               }
-       _found:
-               wake_up(&ctl->change_sleep);
-               spin_unlock(&ctl->read_lock);
                snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN);
        }
-       read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
 }
 EXPORT_SYMBOL(snd_ctl_notify);
 
@@ -210,10 +206,9 @@ void snd_ctl_notify_one(struct snd_card *card, unsigned int mask,
        id.index += ioff;
        id.numid += ioff;
        snd_ctl_notify(card, mask, &id);
-       down_read(&snd_ctl_layer_rwsem);
+       guard(rwsem_read)(&snd_ctl_layer_rwsem);
        for (lops = snd_ctl_layer; lops; lops = lops->next)
                lops->lnotify(card, mask, kctl, ioff);
-       up_read(&snd_ctl_layer_rwsem);
 }
 EXPORT_SYMBOL(snd_ctl_notify_one);
 
@@ -520,9 +515,9 @@ static int snd_ctl_add_replace(struct snd_card *card,
        if (snd_BUG_ON(!card || !kcontrol->info))
                goto error;
 
-       down_write(&card->controls_rwsem);
-       err = __snd_ctl_add_replace(card, kcontrol, mode);
-       up_write(&card->controls_rwsem);
+       scoped_guard(rwsem_write, &card->controls_rwsem)
+               err = __snd_ctl_add_replace(card, kcontrol, mode);
+
        if (err < 0)
                goto error;
        return 0;
@@ -616,12 +611,8 @@ static inline int snd_ctl_remove_locked(struct snd_card *card,
  */
 int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
 {
-       int ret;
-
-       down_write(&card->controls_rwsem);
-       ret = snd_ctl_remove_locked(card, kcontrol);
-       up_write(&card->controls_rwsem);
-       return ret;
+       guard(rwsem_write)(&card->controls_rwsem);
+       return snd_ctl_remove_locked(card, kcontrol);
 }
 EXPORT_SYMBOL(snd_ctl_remove);
 
@@ -638,17 +629,12 @@ EXPORT_SYMBOL(snd_ctl_remove);
 int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
 {
        struct snd_kcontrol *kctl;
-       int ret;
 
-       down_write(&card->controls_rwsem);
+       guard(rwsem_write)(&card->controls_rwsem);
        kctl = snd_ctl_find_id_locked(card, id);
-       if (kctl == NULL) {
-               up_write(&card->controls_rwsem);
+       if (kctl == NULL)
                return -ENOENT;
-       }
-       ret = snd_ctl_remove_locked(card, kctl);
-       up_write(&card->controls_rwsem);
-       return ret;
+       return snd_ctl_remove_locked(card, kctl);
 }
 EXPORT_SYMBOL(snd_ctl_remove_id);
 
@@ -667,27 +653,18 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
 {
        struct snd_card *card = file->card;
        struct snd_kcontrol *kctl;
-       int idx, ret;
+       int idx;
 
-       down_write(&card->controls_rwsem);
+       guard(rwsem_write)(&card->controls_rwsem);
        kctl = snd_ctl_find_id_locked(card, id);
-       if (kctl == NULL) {
-               ret = -ENOENT;
-               goto error;
-       }
-       if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) {
-               ret = -EINVAL;
-               goto error;
-       }
+       if (kctl == NULL)
+               return -ENOENT;
+       if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER))
+               return -EINVAL;
        for (idx = 0; idx < kctl->count; idx++)
-               if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
-                       ret = -EBUSY;
-                       goto error;
-               }
-       ret = snd_ctl_remove_locked(card, kctl);
-error:
-       up_write(&card->controls_rwsem);
-       return ret;
+               if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file)
+                       return -EBUSY;
+       return snd_ctl_remove_locked(card, kctl);
 }
 
 /**
@@ -764,18 +741,15 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
        struct snd_kcontrol *kctl;
        int saved_numid;
 
-       down_write(&card->controls_rwsem);
+       guard(rwsem_write)(&card->controls_rwsem);
        kctl = snd_ctl_find_id_locked(card, src_id);
-       if (kctl == NULL) {
-               up_write(&card->controls_rwsem);
+       if (kctl == NULL)
                return -ENOENT;
-       }
        saved_numid = kctl->id.numid;
        remove_hash_entries(card, kctl);
        kctl->id = *dst_id;
        kctl->id.numid = saved_numid;
        add_hash_entries(card, kctl);
-       up_write(&card->controls_rwsem);
        return 0;
 }
 EXPORT_SYMBOL(snd_ctl_rename_id);
@@ -793,7 +767,7 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
 void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
                    const char *name)
 {
-       down_write(&card->controls_rwsem);
+       guard(rwsem_write)(&card->controls_rwsem);
        remove_hash_entries(card, kctl);
 
        if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0)
@@ -801,7 +775,6 @@ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
                        name, kctl->id.name);
 
        add_hash_entries(card, kctl);
-       up_write(&card->controls_rwsem);
 }
 EXPORT_SYMBOL(snd_ctl_rename);
 
@@ -859,12 +832,8 @@ EXPORT_SYMBOL(snd_ctl_find_numid_locked);
 struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card,
                                        unsigned int numid)
 {
-       struct snd_kcontrol *kctl;
-
-       down_read(&card->controls_rwsem);
-       kctl = snd_ctl_find_numid_locked(card, numid);
-       up_read(&card->controls_rwsem);
-       return kctl;
+       guard(rwsem_read)(&card->controls_rwsem);
+       return snd_ctl_find_numid_locked(card, numid);
 }
 EXPORT_SYMBOL(snd_ctl_find_numid);
 
@@ -920,37 +889,30 @@ EXPORT_SYMBOL(snd_ctl_find_id_locked);
 struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
                                     const struct snd_ctl_elem_id *id)
 {
-       struct snd_kcontrol *kctl;
-
-       down_read(&card->controls_rwsem);
-       kctl = snd_ctl_find_id_locked(card, id);
-       up_read(&card->controls_rwsem);
-       return kctl;
+       guard(rwsem_read)(&card->controls_rwsem);
+       return snd_ctl_find_id_locked(card, id);
 }
 EXPORT_SYMBOL(snd_ctl_find_id);
 
 static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
                             unsigned int cmd, void __user *arg)
 {
-       struct snd_ctl_card_info *info;
+       struct snd_ctl_card_info *info __free(kfree) = NULL;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (! info)
                return -ENOMEM;
-       down_read(&snd_ioctl_rwsem);
-       info->card = card->number;
-       strscpy(info->id, card->id, sizeof(info->id));
-       strscpy(info->driver, card->driver, sizeof(info->driver));
-       strscpy(info->name, card->shortname, sizeof(info->name));
-       strscpy(info->longname, card->longname, sizeof(info->longname));
-       strscpy(info->mixername, card->mixername, sizeof(info->mixername));
-       strscpy(info->components, card->components, sizeof(info->components));
-       up_read(&snd_ioctl_rwsem);
-       if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
-               kfree(info);
+       scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
+               info->card = card->number;
+               strscpy(info->id, card->id, sizeof(info->id));
+               strscpy(info->driver, card->driver, sizeof(info->driver));
+               strscpy(info->name, card->shortname, sizeof(info->name));
+               strscpy(info->longname, card->longname, sizeof(info->longname));
+               strscpy(info->mixername, card->mixername, sizeof(info->mixername));
+               strscpy(info->components, card->components, sizeof(info->components));
+       }
+       if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info)))
                return -EFAULT;
-       }
-       kfree(info);
        return 0;
 }
 
@@ -960,37 +922,31 @@ static int snd_ctl_elem_list(struct snd_card *card,
        struct snd_kcontrol *kctl;
        struct snd_ctl_elem_id id;
        unsigned int offset, space, jidx;
-       int err = 0;
 
        offset = list->offset;
        space = list->space;
 
-       down_read(&card->controls_rwsem);
+       guard(rwsem_read)(&card->controls_rwsem);
        list->count = card->controls_count;
        list->used = 0;
-       if (space > 0) {
-               list_for_each_entry(kctl, &card->controls, list) {
-                       if (offset >= kctl->count) {
-                               offset -= kctl->count;
-                               continue;
-                       }
-                       for (jidx = offset; jidx < kctl->count; jidx++) {
-                               snd_ctl_build_ioff(&id, kctl, jidx);
-                               if (copy_to_user(list->pids + list->used, &id,
-                                                sizeof(id))) {
-                                       err = -EFAULT;
-                                       goto out;
-                               }
-                               list->used++;
-                               if (!--space)
-                                       goto out;
-                       }
-                       offset = 0;
+       if (!space)
+               return 0;
+       list_for_each_entry(kctl, &card->controls, list) {
+               if (offset >= kctl->count) {
+                       offset -= kctl->count;
+                       continue;
                }
+               for (jidx = offset; jidx < kctl->count; jidx++) {
+                       snd_ctl_build_ioff(&id, kctl, jidx);
+                       if (copy_to_user(list->pids + list->used, &id, sizeof(id)))
+                               return -EFAULT;
+                       list->used++;
+                       if (!--space)
+                               return 0;
+               }
+               offset = 0;
        }
- out:
-       up_read(&card->controls_rwsem);
-       return err;
+       return 0;
 }
 
 static int snd_ctl_elem_list_user(struct snd_card *card,
@@ -1238,16 +1194,12 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
 {
        struct snd_card *card = ctl->card;
        struct snd_kcontrol *kctl;
-       int result;
 
-       down_read(&card->controls_rwsem);
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_ctl_find_id_locked(card, &info->id);
-       if (kctl == NULL)
-               result = -ENOENT;
-       else
-               result = __snd_ctl_elem_info(card, kctl, info, ctl);
-       up_read(&card->controls_rwsem);
-       return result;
+       if (!kctl)
+               return -ENOENT;
+       return __snd_ctl_elem_info(card, kctl, info, ctl);
 }
 
 static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
@@ -1279,19 +1231,15 @@ static int snd_ctl_elem_read(struct snd_card *card,
        const u32 pattern = 0xdeadbeef;
        int ret;
 
-       down_read(&card->controls_rwsem);
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_ctl_find_id_locked(card, &control->id);
-       if (kctl == NULL) {
-               ret = -ENOENT;
-               goto unlock;
-       }
+       if (!kctl)
+               return -ENOENT;
 
        index_offset = snd_ctl_get_ioff(kctl, &control->id);
        vd = &kctl->vd[index_offset];
-       if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
-               ret = -EPERM;
-               goto unlock;
-       }
+       if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || !kctl->get)
+               return -EPERM;
 
        snd_ctl_build_ioff(&control->id, kctl, index_offset);
 
@@ -1301,7 +1249,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
        info.id = control->id;
        ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
        if (ret < 0)
-               goto unlock;
+               return ret;
 #endif
 
        if (!snd_ctl_skip_validation(&info))
@@ -1311,7 +1259,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
                ret = kctl->get(kctl, control);
        snd_power_unref(card);
        if (ret < 0)
-               goto unlock;
+               return ret;
        if (!snd_ctl_skip_validation(&info) &&
            sanity_check_elem_value(card, control, &info, pattern) < 0) {
                dev_err(card->dev,
@@ -1319,32 +1267,27 @@ static int snd_ctl_elem_read(struct snd_card *card,
                        control->id.iface, control->id.device,
                        control->id.subdevice, control->id.name,
                        control->id.index);
-               ret = -EINVAL;
-               goto unlock;
+               return -EINVAL;
        }
-unlock:
-       up_read(&card->controls_rwsem);
-       return ret;
+       return 0;
 }
 
 static int snd_ctl_elem_read_user(struct snd_card *card,
                                  struct snd_ctl_elem_value __user *_control)
 {
-       struct snd_ctl_elem_value *control;
+       struct snd_ctl_elem_value *control __free(kfree) = NULL;
        int result;
 
        control = memdup_user(_control, sizeof(*control));
        if (IS_ERR(control))
-               return PTR_ERR(control);
+               return PTR_ERR(no_free_ptr(control));
 
        result = snd_ctl_elem_read(card, control);
        if (result < 0)
-               goto error;
+               return result;
 
        if (copy_to_user(_control, control, sizeof(*control)))
-               result = -EFAULT;
- error:
-       kfree(control);
+               return -EFAULT;
        return result;
 }
 
@@ -1406,23 +1349,21 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
 static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
                                   struct snd_ctl_elem_value __user *_control)
 {
-       struct snd_ctl_elem_value *control;
+       struct snd_ctl_elem_value *control __free(kfree) = NULL;
        struct snd_card *card;
        int result;
 
        control = memdup_user(_control, sizeof(*control));
        if (IS_ERR(control))
-               return PTR_ERR(control);
+               return PTR_ERR(no_free_ptr(control));
 
        card = file->card;
        result = snd_ctl_elem_write(card, file, control);
        if (result < 0)
-               goto error;
+               return result;
 
        if (copy_to_user(_control, control, sizeof(*control)))
-               result = -EFAULT;
- error:
-       kfree(control);
+               return -EFAULT;
        return result;
 }
 
@@ -1433,25 +1374,18 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
        struct snd_ctl_elem_id id;
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_volatile *vd;
-       int result;
 
        if (copy_from_user(&id, _id, sizeof(id)))
                return -EFAULT;
-       down_write(&card->controls_rwsem);
+       guard(rwsem_write)(&card->controls_rwsem);
        kctl = snd_ctl_find_id_locked(card, &id);
-       if (kctl == NULL) {
-               result = -ENOENT;
-       } else {
-               vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
-               if (vd->owner != NULL)
-                       result = -EBUSY;
-               else {
-                       vd->owner = file;
-                       result = 0;
-               }
-       }
-       up_write(&card->controls_rwsem);
-       return result;
+       if (!kctl)
+               return -ENOENT;
+       vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
+       if (vd->owner)
+               return -EBUSY;
+       vd->owner = file;
+       return 0;
 }
 
 static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
@@ -1461,27 +1395,20 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
        struct snd_ctl_elem_id id;
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_volatile *vd;
-       int result;
 
        if (copy_from_user(&id, _id, sizeof(id)))
                return -EFAULT;
-       down_write(&card->controls_rwsem);
+       guard(rwsem_write)(&card->controls_rwsem);
        kctl = snd_ctl_find_id_locked(card, &id);
-       if (kctl == NULL) {
-               result = -ENOENT;
-       } else {
-               vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
-               if (vd->owner == NULL)
-                       result = -EINVAL;
-               else if (vd->owner != file)
-                       result = -EPERM;
-               else {
-                       vd->owner = NULL;
-                       result = 0;
-               }
-       }
-       up_write(&card->controls_rwsem);
-       return result;
+       if (!kctl)
+               return -ENOENT;
+       vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
+       if (!vd->owner)
+               return -EINVAL;
+       if (vd->owner != file)
+               return -EPERM;
+       vd->owner = NULL;
+       return 0;
 }
 
 struct user_element {
@@ -1763,11 +1690,9 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
        private_size = value_sizes[info->type] * info->count;
        alloc_size = compute_user_elem_size(private_size, count);
 
-       down_write(&card->controls_rwsem);
-       if (check_user_elem_overflow(card, alloc_size)) {
-               err = -ENOMEM;
-               goto unlock;
-       }
+       guard(rwsem_write)(&card->controls_rwsem);
+       if (check_user_elem_overflow(card, alloc_size))
+               return -ENOMEM;
 
        /*
         * Keep memory object for this userspace control. After passing this
@@ -1777,13 +1702,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
         */
        err = snd_ctl_new(&kctl, count, access, file);
        if (err < 0)
-               goto unlock;
+               return err;
        memcpy(&kctl->id, &info->id, sizeof(kctl->id));
        ue = kzalloc(alloc_size, GFP_KERNEL);
        if (!ue) {
                kfree(kctl);
-               err = -ENOMEM;
-               goto unlock;
+               return -ENOMEM;
        }
        kctl->private_data = ue;
        kctl->private_free = snd_ctl_elem_user_free;
@@ -1801,7 +1725,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
                err = snd_ctl_elem_init_enum_names(ue);
                if (err < 0) {
                        snd_ctl_free_one(kctl);
-                       goto unlock;
+                       return err;
                }
        }
 
@@ -1821,7 +1745,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
        err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
        if (err < 0) {
                snd_ctl_free_one(kctl);
-               goto unlock;
+               return err;
        }
        offset = snd_ctl_get_ioff(kctl, &info->id);
        snd_ctl_build_ioff(&info->id, kctl, offset);
@@ -1832,9 +1756,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
         * applications because the field originally means PID of a process
         * which locks the element.
         */
- unlock:
-       up_write(&card->controls_rwsem);
-       return err;
+       return 0;
 }
 
 static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
@@ -2036,34 +1958,29 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
        case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
                return snd_ctl_subscribe_events(ctl, ip);
        case SNDRV_CTL_IOCTL_TLV_READ:
-               down_read(&ctl->card->controls_rwsem);
-               err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
-               up_read(&ctl->card->controls_rwsem);
+               scoped_guard(rwsem_read, &ctl->card->controls_rwsem)
+                       err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
                return err;
        case SNDRV_CTL_IOCTL_TLV_WRITE:
-               down_write(&ctl->card->controls_rwsem);
-               err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
-               up_write(&ctl->card->controls_rwsem);
+               scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
+                       err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
                return err;
        case SNDRV_CTL_IOCTL_TLV_COMMAND:
-               down_write(&ctl->card->controls_rwsem);
-               err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
-               up_write(&ctl->card->controls_rwsem);
+               scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
+                       err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
                return err;
        case SNDRV_CTL_IOCTL_POWER:
                return -ENOPROTOOPT;
        case SNDRV_CTL_IOCTL_POWER_STATE:
                return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
        }
-       down_read(&snd_ioctl_rwsem);
+
+       guard(rwsem_read)(&snd_ioctl_rwsem);
        list_for_each_entry(p, &snd_control_ioctls, list) {
                err = p->fioctl(card, ctl, cmd, arg);
-               if (err != -ENOIOCTLCMD) {
-                       up_read(&snd_ioctl_rwsem);
+               if (err != -ENOIOCTLCMD)
                        return err;
-               }
        }
-       up_read(&snd_ioctl_rwsem);
        dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
        return -ENOTTY;
 }
@@ -2155,9 +2072,8 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *
        if (pn == NULL)
                return -ENOMEM;
        pn->fioctl = fcn;
-       down_write(&snd_ioctl_rwsem);
+       guard(rwsem_write)(&snd_ioctl_rwsem);
        list_add_tail(&pn->list, lists);
-       up_write(&snd_ioctl_rwsem);
        return 0;
 }
 
@@ -2200,16 +2116,14 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
 
        if (snd_BUG_ON(!fcn))
                return -EINVAL;
-       down_write(&snd_ioctl_rwsem);
+       guard(rwsem_write)(&snd_ioctl_rwsem);
        list_for_each_entry(p, lists, list) {
                if (p->fioctl == fcn) {
                        list_del(&p->list);
-                       up_write(&snd_ioctl_rwsem);
                        kfree(p);
                        return 0;
                }
        }
-       up_write(&snd_ioctl_rwsem);
        snd_BUG();
        return -EINVAL;
 }
@@ -2256,9 +2170,8 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
 {
        struct snd_ctl_file *kctl;
        int subdevice = -1;
-       unsigned long flags;
 
-       read_lock_irqsave(&card->ctl_files_rwlock, flags);
+       guard(read_lock_irqsave)(&card->ctl_files_rwlock);
        list_for_each_entry(kctl, &card->ctl_files, list) {
                if (kctl->pid == task_pid(current)) {
                        subdevice = kctl->preferred_subdevice[type];
@@ -2266,7 +2179,6 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
                                break;
                }
        }
-       read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
        return subdevice;
 }
 EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
@@ -2296,13 +2208,11 @@ int snd_ctl_request_layer(const char *module_name)
 
        if (module_name == NULL)
                return 0;
-       down_read(&snd_ctl_layer_rwsem);
-       for (lops = snd_ctl_layer; lops; lops = lops->next)
-               if (strcmp(lops->module_name, module_name) == 0)
-                       break;
-       up_read(&snd_ctl_layer_rwsem);
-       if (lops)
-               return 0;
+       scoped_guard(rwsem_read, &snd_ctl_layer_rwsem) {
+               for (lops = snd_ctl_layer; lops; lops = lops->next)
+                       if (strcmp(lops->module_name, module_name) == 0)
+                               return 0;
+       }
        return request_module(module_name);
 }
 EXPORT_SYMBOL_GPL(snd_ctl_request_layer);
@@ -2319,16 +2229,15 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
        struct snd_card *card;
        int card_number;
 
-       down_write(&snd_ctl_layer_rwsem);
-       lops->next = snd_ctl_layer;
-       snd_ctl_layer = lops;
-       up_write(&snd_ctl_layer_rwsem);
+       scoped_guard(rwsem_write, &snd_ctl_layer_rwsem) {
+               lops->next = snd_ctl_layer;
+               snd_ctl_layer = lops;
+       }
        for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
                card = snd_card_ref(card_number);
                if (card) {
-                       down_read(&card->controls_rwsem);
-                       lops->lregister(card);
-                       up_read(&card->controls_rwsem);
+                       scoped_guard(rwsem_read, &card->controls_rwsem)
+                               lops->lregister(card);
                        snd_card_unref(card);
                }
        }
@@ -2347,7 +2256,7 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
 {
        struct snd_ctl_layer_ops *lops2, *prev_lops2;
 
-       down_write(&snd_ctl_layer_rwsem);
+       guard(rwsem_write)(&snd_ctl_layer_rwsem);
        for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) {
                if (lops2 == lops) {
                        if (!prev_lops2)
@@ -2358,7 +2267,6 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
                }
                prev_lops2 = lops2;
        }
-       up_write(&snd_ctl_layer_rwsem);
 }
 EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer);
 
@@ -2379,25 +2287,29 @@ static const struct file_operations snd_ctl_f_ops =
        .fasync =       snd_ctl_fasync,
 };
 
+/* call lops under rwsems; called from snd_ctl_dev_*() below() */
+#define call_snd_ctl_lops(_card, _op)                              \
+       do {                                                        \
+               struct snd_ctl_layer_ops *lops;                     \
+               guard(rwsem_read)(&(_card)->controls_rwsem);        \
+               guard(rwsem_read)(&snd_ctl_layer_rwsem);            \
+               for (lops = snd_ctl_layer; lops; lops = lops->next) \
+                       lops->_op(_card);                           \
+       } while (0)
+
 /*
  * registration of the control device
  */
 static int snd_ctl_dev_register(struct snd_device *device)
 {
        struct snd_card *card = device->device_data;
-       struct snd_ctl_layer_ops *lops;
        int err;
 
        err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
                                  &snd_ctl_f_ops, card, card->ctl_dev);
        if (err < 0)
                return err;
-       down_read(&card->controls_rwsem);
-       down_read(&snd_ctl_layer_rwsem);
-       for (lops = snd_ctl_layer; lops; lops = lops->next)
-               lops->lregister(card);
-       up_read(&snd_ctl_layer_rwsem);
-       up_read(&card->controls_rwsem);
+       call_snd_ctl_lops(card, lregister);
        return 0;
 }
 
@@ -2408,23 +2320,15 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
 {
        struct snd_card *card = device->device_data;
        struct snd_ctl_file *ctl;
-       struct snd_ctl_layer_ops *lops;
-       unsigned long flags;
 
-       read_lock_irqsave(&card->ctl_files_rwlock, flags);
-       list_for_each_entry(ctl, &card->ctl_files, list) {
-               wake_up(&ctl->change_sleep);
-               snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
+       scoped_guard(read_lock_irqsave, &card->ctl_files_rwlock) {
+               list_for_each_entry(ctl, &card->ctl_files, list) {
+                       wake_up(&ctl->change_sleep);
+                       snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
+               }
        }
-       read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
-
-       down_read(&card->controls_rwsem);
-       down_read(&snd_ctl_layer_rwsem);
-       for (lops = snd_ctl_layer; lops; lops = lops->next)
-               lops->ldisconnect(card);
-       up_read(&snd_ctl_layer_rwsem);
-       up_read(&card->controls_rwsem);
 
+       call_snd_ctl_lops(card, ldisconnect);
        return snd_unregister_device(card->ctl_dev);
 }
 
@@ -2436,17 +2340,17 @@ static int snd_ctl_dev_free(struct snd_device *device)
        struct snd_card *card = device->device_data;
        struct snd_kcontrol *control;
 
-       down_write(&card->controls_rwsem);
-       while (!list_empty(&card->controls)) {
-               control = snd_kcontrol(card->controls.next);
-               __snd_ctl_remove(card, control, false);
-       }
+       scoped_guard(rwsem_write, &card->controls_rwsem) {
+               while (!list_empty(&card->controls)) {
+                       control = snd_kcontrol(card->controls.next);
+                       __snd_ctl_remove(card, control, false);
+               }
 
 #ifdef CONFIG_SND_CTL_FAST_LOOKUP
-       xa_destroy(&card->ctl_numids);
-       xa_destroy(&card->ctl_hash);
+               xa_destroy(&card->ctl_numids);
+               xa_destroy(&card->ctl_hash);
 #endif
-       up_write(&card->controls_rwsem);
+       }
        put_device(card->ctl_dev);
        return 0;
 }
index 63d787501066c907dd5efcdccea52960e8a7c44b..934bb945e702a2090bb103c6e5e20a222d393dd7 100644 (file)
@@ -79,61 +79,56 @@ struct snd_ctl_elem_info32 {
 static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
                                    struct snd_ctl_elem_info32 __user *data32)
 {
-       struct snd_ctl_elem_info *data;
+       struct snd_ctl_elem_info *data __free(kfree) = NULL;
        int err;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (! data)
                return -ENOMEM;
 
-       err = -EFAULT;
        /* copy id */
        if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
-               goto error;
+               return -EFAULT;
        /* we need to copy the item index.
         * hope this doesn't break anything..
         */
        if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
-               goto error;
+               return -EFAULT;
 
        err = snd_ctl_elem_info(ctl, data);
        if (err < 0)
-               goto error;
+               return err;
        /* restore info to 32bit */
-       err = -EFAULT;
        /* id, type, access, count */
        if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
            copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
-               goto error;
+               return -EFAULT;
        if (put_user(data->owner, &data32->owner))
-               goto error;
+               return -EFAULT;
        switch (data->type) {
        case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
        case SNDRV_CTL_ELEM_TYPE_INTEGER:
                if (put_user(data->value.integer.min, &data32->value.integer.min) ||
                    put_user(data->value.integer.max, &data32->value.integer.max) ||
                    put_user(data->value.integer.step, &data32->value.integer.step))
-                       goto error;
+                       return -EFAULT;
                break;
        case SNDRV_CTL_ELEM_TYPE_INTEGER64:
                if (copy_to_user(&data32->value.integer64,
                                 &data->value.integer64,
                                 sizeof(data->value.integer64)))
-                       goto error;
+                       return -EFAULT;
                break;
        case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
                if (copy_to_user(&data32->value.enumerated,
                                 &data->value.enumerated,
                                 sizeof(data->value.enumerated)))
-                       goto error;
+                       return -EFAULT;
                break;
        default:
                break;
        }
-       err = 0;
- error:
-       kfree(data);
-       return err;
+       return 0;
 }
 
 /* read / write */
@@ -169,31 +164,25 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
                        int *countp)
 {
        struct snd_kcontrol *kctl;
-       struct snd_ctl_elem_info *info;
+       struct snd_ctl_elem_info *info __free(kfree) = NULL;
        int err;
 
-       down_read(&card->controls_rwsem);
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_ctl_find_id_locked(card, id);
-       if (! kctl) {
-               up_read(&card->controls_rwsem);
+       if (!kctl)
                return -ENOENT;
-       }
        info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (info == NULL) {
-               up_read(&card->controls_rwsem);
+       if (info == NULL)
                return -ENOMEM;
-       }
        info->id = *id;
        err = snd_power_ref_and_wait(card);
        if (!err)
                err = kctl->info(kctl, info);
        snd_power_unref(card);
-       up_read(&card->controls_rwsem);
        if (err >= 0) {
                err = info->type;
                *countp = info->count;
        }
-       kfree(info);
        return err;
 }
 
@@ -289,7 +278,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
 static int ctl_elem_read_user(struct snd_card *card,
                              void __user *userdata, void __user *valuep)
 {
-       struct snd_ctl_elem_value *data;
+       struct snd_ctl_elem_value *data __free(kfree) = NULL;
        int err, type, count;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -299,21 +288,18 @@ static int ctl_elem_read_user(struct snd_card *card,
        err = copy_ctl_value_from_user(card, data, userdata, valuep,
                                       &type, &count);
        if (err < 0)
-               goto error;
+               return err;
 
        err = snd_ctl_elem_read(card, data);
        if (err < 0)
-               goto error;
-       err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
- error:
-       kfree(data);
-       return err;
+               return err;
+       return copy_ctl_value_to_user(userdata, valuep, data, type, count);
 }
 
 static int ctl_elem_write_user(struct snd_ctl_file *file,
                               void __user *userdata, void __user *valuep)
 {
-       struct snd_ctl_elem_value *data;
+       struct snd_ctl_elem_value *data __free(kfree) = NULL;
        struct snd_card *card = file->card;
        int err, type, count;
 
@@ -324,15 +310,12 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
        err = copy_ctl_value_from_user(card, data, userdata, valuep,
                                       &type, &count);
        if (err < 0)
-               goto error;
+               return err;
 
        err = snd_ctl_elem_write(card, file, data);
        if (err < 0)
-               goto error;
-       err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
- error:
-       kfree(data);
-       return err;
+               return err;
+       return copy_ctl_value_to_user(userdata, valuep, data, type, count);
 }
 
 static int snd_ctl_elem_read_user_compat(struct snd_card *card,
@@ -366,49 +349,44 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
                                   struct snd_ctl_elem_info32 __user *data32,
                                   int replace)
 {
-       struct snd_ctl_elem_info *data;
-       int err;
+       struct snd_ctl_elem_info *data __free(kfree) = NULL;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (! data)
                return -ENOMEM;
 
-       err = -EFAULT;
        /* id, type, access, count */ \
        if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
            copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
-               goto error;
+               return -EFAULT;
        if (get_user(data->owner, &data32->owner))
-               goto error;
+               return -EFAULT;
        switch (data->type) {
        case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
        case SNDRV_CTL_ELEM_TYPE_INTEGER:
                if (get_user(data->value.integer.min, &data32->value.integer.min) ||
                    get_user(data->value.integer.max, &data32->value.integer.max) ||
                    get_user(data->value.integer.step, &data32->value.integer.step))
-                       goto error;
+                       return -EFAULT;
                break;
        case SNDRV_CTL_ELEM_TYPE_INTEGER64:
                if (copy_from_user(&data->value.integer64,
                                   &data32->value.integer64,
                                   sizeof(data->value.integer64)))
-                       goto error;
+                       return -EFAULT;
                break;
        case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
                if (copy_from_user(&data->value.enumerated,
                                   &data32->value.enumerated,
                                   sizeof(data->value.enumerated)))
-                       goto error;
+                       return -EFAULT;
                data->value.enumerated.names_ptr =
                        (uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
                break;
        default:
                break;
        }
-       err = snd_ctl_elem_add(file, data, replace);
- error:
-       kfree(data);
-       return err;
+       return snd_ctl_elem_add(file, data, replace);
 }  
 
 enum {
@@ -468,16 +446,13 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
 #endif /* CONFIG_X86_X32_ABI */
        }
 
-       down_read(&snd_ioctl_rwsem);
+       guard(rwsem_read)(&snd_ioctl_rwsem);
        list_for_each_entry(p, &snd_control_compat_ioctls, list) {
                if (p->fioctl) {
                        err = p->fioctl(ctl->card, ctl, cmd, arg);
-                       if (err != -ENOIOCTLCMD) {
-                               up_read(&snd_ioctl_rwsem);
+                       if (err != -ENOIOCTLCMD)
                                return err;
-                       }
                }
        }
-       up_read(&snd_ioctl_rwsem);
        return -ENOIOCTLCMD;
 }
index a78eb48927c7bfa68354a6fa80dcb740f71c9ed5..3d37e9fa7b9c207d9b24fa3bcd4507550d727316 100644 (file)
@@ -147,29 +147,27 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
                return;
        route = -1;
        found = false;
-       mutex_lock(&snd_ctl_led_mutex);
-       /* the card may not be registered (active) at this point */
-       if (card && !snd_ctl_led_card_valid[card->number]) {
-               mutex_unlock(&snd_ctl_led_mutex);
-               return;
-       }
-       list_for_each_entry(lctl, &led->controls, list) {
-               if (lctl->kctl == kctl && lctl->index_offset == ioff)
-                       found = true;
-               UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
-       }
-       if (!found && kctl && card) {
-               lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
-               if (lctl) {
-                       lctl->card = card;
-                       lctl->access = access;
-                       lctl->kctl = kctl;
-                       lctl->index_offset = ioff;
-                       list_add(&lctl->list, &led->controls);
+       scoped_guard(mutex, &snd_ctl_led_mutex) {
+               /* the card may not be registered (active) at this point */
+               if (card && !snd_ctl_led_card_valid[card->number])
+                       return;
+               list_for_each_entry(lctl, &led->controls, list) {
+                       if (lctl->kctl == kctl && lctl->index_offset == ioff)
+                               found = true;
                        UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
                }
+               if (!found && kctl && card) {
+                       lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
+                       if (lctl) {
+                               lctl->card = card;
+                               lctl->access = access;
+                               lctl->kctl = kctl;
+                               lctl->index_offset = ioff;
+                               list_add(&lctl->list, &led->controls);
+                               UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
+                       }
+               }
        }
-       mutex_unlock(&snd_ctl_led_mutex);
        switch (led->mode) {
        case MODE_OFF:          route = 1; break;
        case MODE_ON:           route = 0; break;
@@ -201,14 +199,13 @@ static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int i
        struct snd_ctl_led_ctl *lctl;
        unsigned int ret = 0;
 
-       mutex_lock(&snd_ctl_led_mutex);
+       guard(mutex)(&snd_ctl_led_mutex);
        lctl = snd_ctl_led_find(kctl, ioff);
        if (lctl && (access == 0 || access != lctl->access)) {
                ret = lctl->access;
                list_del(&lctl->list);
                kfree(lctl);
        }
-       mutex_unlock(&snd_ctl_led_mutex);
        return ret;
 }
 
@@ -239,44 +236,36 @@ static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask,
        }
 }
 
+DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T))
+
 static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
                              unsigned int group, bool set)
 {
-       struct snd_card *card;
+       struct snd_card *card __free(snd_card_unref) = NULL;
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_volatile *vd;
        unsigned int ioff, access, new_access;
-       int err = 0;
 
        card = snd_card_ref(card_number);
-       if (card) {
-               down_write(&card->controls_rwsem);
-               kctl = snd_ctl_find_id_locked(card, id);
-               if (kctl) {
-                       ioff = snd_ctl_get_ioff(kctl, id);
-                       vd = &kctl->vd[ioff];
-                       access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
-                       if (access != 0 && access != group_to_access(group)) {
-                               err = -EXDEV;
-                               goto unlock;
-                       }
-                       new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
-                       if (set)
-                               new_access |= group_to_access(group);
-                       if (new_access != vd->access) {
-                               vd->access = new_access;
-                               snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
-                       }
-               } else {
-                       err = -ENOENT;
-               }
-unlock:
-               up_write(&card->controls_rwsem);
-               snd_card_unref(card);
-       } else {
-               err = -ENXIO;
+       if (!card)
+               return -ENXIO;
+       guard(rwsem_write)(&card->controls_rwsem);
+       kctl = snd_ctl_find_id_locked(card, id);
+       if (!kctl)
+               return -ENOENT;
+       ioff = snd_ctl_get_ioff(kctl, id);
+       vd = &kctl->vd[ioff];
+       access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
+       if (access != 0 && access != group_to_access(group))
+               return -EXDEV;
+       new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
+       if (set)
+               new_access |= group_to_access(group);
+       if (new_access != vd->access) {
+               vd->access = new_access;
+               snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
        }
-       return err;
+       return 0;
 }
 
 static void snd_ctl_led_refresh(void)
@@ -312,7 +301,7 @@ repeat:
 
 static int snd_ctl_led_reset(int card_number, unsigned int group)
 {
-       struct snd_card *card;
+       struct snd_card *card __free(snd_card_unref) = NULL;
        struct snd_ctl_led *led;
        struct snd_ctl_led_ctl *lctl;
        struct snd_kcontrol_volatile *vd;
@@ -322,26 +311,22 @@ static int snd_ctl_led_reset(int card_number, unsigned int group)
        if (!card)
                return -ENXIO;
 
-       mutex_lock(&snd_ctl_led_mutex);
-       if (!snd_ctl_led_card_valid[card_number]) {
-               mutex_unlock(&snd_ctl_led_mutex);
-               snd_card_unref(card);
-               return -ENXIO;
-       }
-       led = &snd_ctl_leds[group];
+       scoped_guard(mutex, &snd_ctl_led_mutex) {
+               if (!snd_ctl_led_card_valid[card_number])
+                       return -ENXIO;
+               led = &snd_ctl_leds[group];
 repeat:
-       list_for_each_entry(lctl, &led->controls, list)
-               if (lctl->card == card) {
-                       vd = &lctl->kctl->vd[lctl->index_offset];
-                       vd->access &= ~group_to_access(group);
-                       snd_ctl_led_ctl_destroy(lctl);
-                       change = true;
-                       goto repeat;
-               }
-       mutex_unlock(&snd_ctl_led_mutex);
+               list_for_each_entry(lctl, &led->controls, list)
+                       if (lctl->card == card) {
+                               vd = &lctl->kctl->vd[lctl->index_offset];
+                               vd->access &= ~group_to_access(group);
+                               snd_ctl_led_ctl_destroy(lctl);
+                               change = true;
+                               goto repeat;
+                       }
+       }
        if (change)
                snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
-       snd_card_unref(card);
        return 0;
 }
 
@@ -353,9 +338,8 @@ static void snd_ctl_led_register(struct snd_card *card)
        if (snd_BUG_ON(card->number < 0 ||
                       card->number >= ARRAY_SIZE(snd_ctl_led_card_valid)))
                return;
-       mutex_lock(&snd_ctl_led_mutex);
-       snd_ctl_led_card_valid[card->number] = true;
-       mutex_unlock(&snd_ctl_led_mutex);
+       scoped_guard(mutex, &snd_ctl_led_mutex)
+               snd_ctl_led_card_valid[card->number] = true;
        /* the register callback is already called with held card->controls_rwsem */
        list_for_each_entry(kctl, &card->controls, list)
                for (ioff = 0; ioff < kctl->count; ioff++)
@@ -367,10 +351,10 @@ static void snd_ctl_led_register(struct snd_card *card)
 static void snd_ctl_led_disconnect(struct snd_card *card)
 {
        snd_ctl_led_sysfs_remove(card);
-       mutex_lock(&snd_ctl_led_mutex);
-       snd_ctl_led_card_valid[card->number] = false;
-       snd_ctl_led_clean(card);
-       mutex_unlock(&snd_ctl_led_mutex);
+       scoped_guard(mutex, &snd_ctl_led_mutex) {
+               snd_ctl_led_card_valid[card->number] = false;
+               snd_ctl_led_clean(card);
+       }
        snd_ctl_led_refresh();
 }
 
@@ -430,9 +414,8 @@ static ssize_t mode_store(struct device *dev,
        else
                return count;
 
-       mutex_lock(&snd_ctl_led_mutex);
-       led->mode = mode;
-       mutex_unlock(&snd_ctl_led_mutex);
+       scoped_guard(mutex, &snd_ctl_led_mutex)
+               led->mode = mode;
 
        snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0);
        return count;
@@ -615,15 +598,15 @@ static ssize_t list_show(struct device *dev,
                         struct device_attribute *attr, char *buf)
 {
        struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
-       struct snd_card *card;
+       struct snd_card *card __free(snd_card_unref) = NULL;
        struct snd_ctl_led_ctl *lctl;
        size_t l = 0;
 
        card = snd_card_ref(led_card->number);
        if (!card)
                return -ENXIO;
-       down_read(&card->controls_rwsem);
-       mutex_lock(&snd_ctl_led_mutex);
+       guard(rwsem_read)(&card->controls_rwsem);
+       guard(mutex)(&snd_ctl_led_mutex);
        if (snd_ctl_led_card_valid[led_card->number]) {
                list_for_each_entry(lctl, &led_card->led->controls, list) {
                        if (lctl->card != card)
@@ -634,9 +617,6 @@ static ssize_t list_show(struct device *dev,
                                           lctl->kctl->id.numid + lctl->index_offset);
                }
        }
-       mutex_unlock(&snd_ctl_led_mutex);
-       up_read(&card->controls_rwsem);
-       snd_card_unref(card);
        return l;
 }
 
index e97ff8cccb643359cae97162040f516a7b0c43b1..147c1fea4708efe3bb3d1f7faed8923633f49e9c 100644 (file)
@@ -35,12 +35,12 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
        unsigned long ticks;
        enum hrtimer_restart ret = HRTIMER_NORESTART;
 
-       spin_lock(&t->lock);
-       if (!t->running)
-               goto out; /* fast path */
-       stime->in_callback = true;
-       ticks = t->sticks;
-       spin_unlock(&t->lock);
+       scoped_guard(spinlock, &t->lock) {
+               if (!t->running)
+                       return HRTIMER_NORESTART; /* fast path */
+               stime->in_callback = true;
+               ticks = t->sticks;
+       }
 
        /* calculate the drift */
        delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
@@ -49,15 +49,13 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
 
        snd_timer_interrupt(stime->timer, ticks);
 
-       spin_lock(&t->lock);
+       guard(spinlock)(&t->lock);
        if (t->running) {
                hrtimer_add_expires_ns(hrt, t->sticks * resolution);
                ret = HRTIMER_RESTART;
        }
 
        stime->in_callback = false;
- out:
-       spin_unlock(&t->lock);
        return ret;
 }
 
@@ -80,10 +78,10 @@ static int snd_hrtimer_close(struct snd_timer *t)
        struct snd_hrtimer *stime = t->private_data;
 
        if (stime) {
-               spin_lock_irq(&t->lock);
-               t->running = 0; /* just to be sure */
-               stime->in_callback = 1; /* skip start/stop */
-               spin_unlock_irq(&t->lock);
+               scoped_guard(spinlock_irq, &t->lock) {
+                       t->running = 0; /* just to be sure */
+                       stime->in_callback = 1; /* skip start/stop */
+               }
 
                hrtimer_cancel(&stime->hrt);
                kfree(stime);
index de7476034f2cf5f495c634a2a1649a543aab2811..09200df2932c793104acf91fedf005cf51fac30b 100644 (file)
@@ -149,12 +149,12 @@ static int snd_hwdep_release(struct inode *inode, struct file * file)
        struct snd_hwdep *hw = file->private_data;
        struct module *mod = hw->card->module;
 
-       mutex_lock(&hw->open_mutex);
-       if (hw->ops.release)
-               err = hw->ops.release(hw, file);
-       if (hw->used > 0)
-               hw->used--;
-       mutex_unlock(&hw->open_mutex);
+       scoped_guard(mutex, &hw->open_mutex) {
+               if (hw->ops.release)
+                       err = hw->ops.release(hw, file);
+               if (hw->used > 0)
+                       hw->used--;
+       }
        wake_up(&hw->open_wait);
 
        snd_card_file_remove(hw->card, file);
@@ -272,23 +272,23 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
 
                        if (get_user(device, (int __user *)arg))
                                return -EFAULT;
-                       mutex_lock(&register_mutex);
-
-                       if (device < 0)
-                               device = 0;
-                       else if (device < SNDRV_MINOR_HWDEPS)
-                               device++;
-                       else
-                               device = SNDRV_MINOR_HWDEPS;
-
-                       while (device < SNDRV_MINOR_HWDEPS) {
-                               if (snd_hwdep_search(card, device))
-                                       break;
-                               device++;
+
+                       scoped_guard(mutex, &register_mutex) {
+                               if (device < 0)
+                                       device = 0;
+                               else if (device < SNDRV_MINOR_HWDEPS)
+                                       device++;
+                               else
+                                       device = SNDRV_MINOR_HWDEPS;
+
+                               while (device < SNDRV_MINOR_HWDEPS) {
+                                       if (snd_hwdep_search(card, device))
+                                               break;
+                                       device++;
+                               }
+                               if (device >= SNDRV_MINOR_HWDEPS)
+                                       device = -1;
                        }
-                       if (device >= SNDRV_MINOR_HWDEPS)
-                               device = -1;
-                       mutex_unlock(&register_mutex);
                        if (put_user(device, (int __user *)arg))
                                return -EFAULT;
                        return 0;
@@ -296,19 +296,18 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
        case SNDRV_CTL_IOCTL_HWDEP_INFO:
                {
                        struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg;
-                       int device, err;
+                       int device;
                        struct snd_hwdep *hwdep;
 
                        if (get_user(device, &info->device))
                                return -EFAULT;
-                       mutex_lock(&register_mutex);
-                       hwdep = snd_hwdep_search(card, device);
-                       if (hwdep)
-                               err = snd_hwdep_info(hwdep, info);
-                       else
-                               err = -ENXIO;
-                       mutex_unlock(&register_mutex);
-                       return err;
+                       scoped_guard(mutex, &register_mutex) {
+                               hwdep = snd_hwdep_search(card, device);
+                               if (!hwdep)
+                                       return -ENXIO;
+                               return snd_hwdep_info(hwdep, info);
+                       }
+                       break;
                }
        }
        return -ENOIOCTLCMD;
@@ -422,11 +421,9 @@ static int snd_hwdep_dev_register(struct snd_device *device)
        struct snd_card *card = hwdep->card;
        int err;
 
-       mutex_lock(&register_mutex);
-       if (snd_hwdep_search(card, hwdep->device)) {
-               mutex_unlock(&register_mutex);
+       guard(mutex)(&register_mutex);
+       if (snd_hwdep_search(card, hwdep->device))
                return -EBUSY;
-       }
        list_add_tail(&hwdep->list, &snd_hwdep_devices);
        err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
                                  hwdep->card, hwdep->device,
@@ -434,7 +431,6 @@ static int snd_hwdep_dev_register(struct snd_device *device)
        if (err < 0) {
                dev_err(hwdep->dev, "unable to register\n");
                list_del(&hwdep->list);
-               mutex_unlock(&register_mutex);
                return err;
        }
 
@@ -454,7 +450,6 @@ static int snd_hwdep_dev_register(struct snd_device *device)
                        hwdep->ossreg = 1;
        }
 #endif
-       mutex_unlock(&register_mutex);
        return 0;
 }
 
@@ -464,12 +459,10 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
 
        if (snd_BUG_ON(!hwdep))
                return -ENXIO;
-       mutex_lock(&register_mutex);
-       if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
-               mutex_unlock(&register_mutex);
+       guard(mutex)(&register_mutex);
+       if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep)
                return -EINVAL;
-       }
-       mutex_lock(&hwdep->open_mutex);
+       guard(mutex)(&hwdep->open_mutex);
        wake_up(&hwdep->open_wait);
 #ifdef CONFIG_SND_OSSEMUL
        if (hwdep->ossreg)
@@ -477,8 +470,6 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
 #endif
        snd_unregister_device(hwdep->dev);
        list_del_init(&hwdep->list);
-       mutex_unlock(&hwdep->open_mutex);
-       mutex_unlock(&register_mutex);
        return 0;
 }
 
@@ -492,11 +483,10 @@ static void snd_hwdep_proc_read(struct snd_info_entry *entry,
 {
        struct snd_hwdep *hwdep;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        list_for_each_entry(hwdep, &snd_hwdep_devices, list)
                snd_iprintf(buffer, "%02i-%02i: %s\n",
                            hwdep->card->number, hwdep->device, hwdep->name);
-       mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_hwdep_proc_entry;
index e2f302e55bbb20de0ee95593a34d26c4745d0ca3..1f5b8a3d9e3b62a5e3796e9394c1de4e98441a1f 100644 (file)
@@ -105,17 +105,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
 {
        struct snd_info_private_data *data;
        struct snd_info_entry *entry;
-       loff_t ret = -EINVAL, size;
+       loff_t size;
 
        data = file->private_data;
        entry = data->entry;
-       mutex_lock(&entry->access);
-       if (entry->c.ops->llseek) {
-               ret = entry->c.ops->llseek(entry,
-                                          data->file_private_data,
-                                          file, offset, orig);
-               goto out;
-       }
+       guard(mutex)(&entry->access);
+       if (entry->c.ops->llseek)
+               return entry->c.ops->llseek(entry,
+                                           data->file_private_data,
+                                           file, offset, orig);
 
        size = entry->size;
        switch (orig) {
@@ -126,21 +124,18 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
                break;
        case SEEK_END:
                if (!size)
-                       goto out;
+                       return -EINVAL;
                offset += size;
                break;
        default:
-               goto out;
+               return -EINVAL;
        }
        if (offset < 0)
-               goto out;
+               return -EINVAL;
        if (size && offset > size)
                offset = size;
        file->f_pos = offset;
-       ret = offset;
- out:
-       mutex_unlock(&entry->access);
-       return ret;
+       return offset;
 }
 
 static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
@@ -238,10 +233,10 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
        struct snd_info_private_data *data;
        int mode, err;
 
-       mutex_lock(&info_mutex);
+       guard(mutex)(&info_mutex);
        err = alloc_info_private(entry, &data);
        if (err < 0)
-               goto unlock;
+               return err;
 
        mode = file->f_flags & O_ACCMODE;
        if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) ||
@@ -257,14 +252,11 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
        }
 
        file->private_data = data;
-       mutex_unlock(&info_mutex);
        return 0;
 
  error:
        kfree(data);
        module_put(entry->module);
- unlock:
-       mutex_unlock(&info_mutex);
        return err;
 }
 
@@ -306,7 +298,6 @@ static ssize_t snd_info_text_entry_write(struct file *file,
        struct snd_info_buffer *buf;
        loff_t pos;
        size_t next;
-       int err = 0;
 
        if (!entry->c.text.write)
                return -EIO;
@@ -317,34 +308,24 @@ static ssize_t snd_info_text_entry_write(struct file *file,
        /* don't handle too large text inputs */
        if (next > 16 * 1024)
                return -EIO;
-       mutex_lock(&entry->access);
+       guard(mutex)(&entry->access);
        buf = data->wbuffer;
        if (!buf) {
                data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL);
-               if (!buf) {
-                       err = -ENOMEM;
-                       goto error;
-               }
+               if (!buf)
+                       return -ENOMEM;
        }
        if (next > buf->len) {
                char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);
-               if (!nbuf) {
-                       err = -ENOMEM;
-                       goto error;
-               }
+               if (!nbuf)
+                       return -ENOMEM;
                kvfree(buf->buffer);
                buf->buffer = nbuf;
                buf->len = PAGE_ALIGN(next);
        }
-       if (copy_from_user(buf->buffer + pos, buffer, count)) {
-               err = -EFAULT;
-               goto error;
-       }
+       if (copy_from_user(buf->buffer + pos, buffer, count))
+               return -EFAULT;
        buf->size = next;
- error:
-       mutex_unlock(&entry->access);
-       if (err < 0)
-               return err;
        *offset = next;
        return count;
 }
@@ -369,10 +350,10 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file)
        struct snd_info_private_data *data;
        int err;
 
-       mutex_lock(&info_mutex);
+       guard(mutex)(&info_mutex);
        err = alloc_info_private(entry, &data);
        if (err < 0)
-               goto unlock;
+               return err;
 
        data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL);
        if (!data->rbuffer) {
@@ -386,15 +367,12 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file)
                err = single_open(file, snd_info_seq_show, data);
        if (err < 0)
                goto error;
-       mutex_unlock(&info_mutex);
        return 0;
 
  error:
        kfree(data->rbuffer);
        kfree(data);
        module_put(entry->module);
- unlock:
-       mutex_unlock(&info_mutex);
        return err;
 }
 
@@ -549,7 +527,7 @@ int snd_info_card_register(struct snd_card *card)
  */
 void snd_info_card_id_change(struct snd_card *card)
 {
-       mutex_lock(&info_mutex);
+       guard(mutex)(&info_mutex);
        if (card->proc_root_link) {
                proc_remove(card->proc_root_link);
                card->proc_root_link = NULL;
@@ -558,7 +536,6 @@ void snd_info_card_id_change(struct snd_card *card)
                card->proc_root_link = proc_symlink(card->id,
                                                    snd_proc_root->p,
                                                    card->proc_root->name);
-       mutex_unlock(&info_mutex);
 }
 
 /*
@@ -574,12 +551,11 @@ void snd_info_card_disconnect(struct snd_card *card)
        if (card->proc_root)
                proc_remove(card->proc_root->p);
 
-       mutex_lock(&info_mutex);
+       guard(mutex)(&info_mutex);
        if (card->proc_root)
                snd_info_clear_entries(card->proc_root);
        card->proc_root_link = NULL;
        card->proc_root = NULL;
-       mutex_unlock(&info_mutex);
 }
 
 /*
@@ -703,9 +679,8 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent,
        entry->parent = parent;
        entry->module = module;
        if (parent) {
-               mutex_lock(&parent->access);
+               guard(mutex)(&parent->access);
                list_add_tail(&entry->list, &parent->children);
-               mutex_unlock(&parent->access);
        }
        return entry;
 }
@@ -775,9 +750,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
                return;
        if (entry->p) {
                proc_remove(entry->p);
-               mutex_lock(&info_mutex);
+               guard(mutex)(&info_mutex);
                snd_info_clear_entries(entry);
-               mutex_unlock(&info_mutex);
        }
 
        /* free all children at first */
@@ -786,9 +760,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
 
        p = entry->parent;
        if (p) {
-               mutex_lock(&p->access);
+               guard(mutex)(&p->access);
                list_del(&entry->list);
-               mutex_unlock(&p->access);
        }
        kfree(entry->name);
        if (entry->private_free)
@@ -804,15 +777,13 @@ static int __snd_info_register(struct snd_info_entry *entry)
        if (snd_BUG_ON(!entry))
                return -ENXIO;
        root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p;
-       mutex_lock(&info_mutex);
+       guard(mutex)(&info_mutex);
        if (entry->p || !root)
-               goto unlock;
+               return 0;
        if (S_ISDIR(entry->mode)) {
                p = proc_mkdir_mode(entry->name, entry->mode, root);
-               if (!p) {
-                       mutex_unlock(&info_mutex);
+               if (!p)
                        return -ENOMEM;
-               }
        } else {
                const struct proc_ops *ops;
                if (entry->content == SNDRV_INFO_CONTENT_DATA)
@@ -821,15 +792,11 @@ static int __snd_info_register(struct snd_info_entry *entry)
                        ops = &snd_info_text_entry_ops;
                p = proc_create_data(entry->name, entry->mode, root,
                                     ops, entry);
-               if (!p) {
-                       mutex_unlock(&info_mutex);
+               if (!p)
                        return -ENOMEM;
-               }
                proc_set_size(p, entry->size);
        }
        entry->p = p;
- unlock:
-       mutex_unlock(&info_mutex);
        return 0;
 }
 
index ebc714b2f46b3faca2db1f0f8b9fee5fd8ba0520..0dbbb80055700ed3509f5f7f991e226a3b256b68 100644 (file)
@@ -29,20 +29,17 @@ int snd_oss_info_register(int dev, int num, char *string)
                return -ENXIO;
        if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS))
                return -ENXIO;
-       mutex_lock(&strings);
+       guard(mutex)(&strings);
        if (string == NULL) {
                x = snd_sndstat_strings[num][dev];
                kfree(x);
                x = NULL;
        } else {
                x = kstrdup(string, GFP_KERNEL);
-               if (x == NULL) {
-                       mutex_unlock(&strings);
+               if (x == NULL)
                        return -ENOMEM;
-               }
        }
        snd_sndstat_strings[num][dev] = x;
-       mutex_unlock(&strings);
        return 0;
 }
 EXPORT_SYMBOL(snd_oss_info_register);
@@ -53,7 +50,7 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
        char *str;
 
        snd_iprintf(buf, "\n%s:", id);
-       mutex_lock(&strings);
+       guard(mutex)(&strings);
        for (idx = 0; idx < SNDRV_CARDS; idx++) {
                str = snd_sndstat_strings[idx][dev];
                if (str) {
@@ -64,7 +61,6 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
                        snd_iprintf(buf, "%i: %s\n", idx, str);
                }
        }
-       mutex_unlock(&strings);
        if (ok < 0)
                snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
        return ok;
index 22c0d217b8608f04b4c9c1803379b9546f12ed14..4ed5037d8693b3ab3472818b82ce2286b99b942c 100644 (file)
@@ -284,30 +284,31 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
        if (xid)
                strscpy(card->id, xid, sizeof(card->id));
        err = 0;
-       mutex_lock(&snd_card_mutex);
-       if (idx < 0) /* first check the matching module-name slot */
-               idx = get_slot_from_bitmask(idx, module_slot_match, module);
-       if (idx < 0) /* if not matched, assign an empty slot */
-               idx = get_slot_from_bitmask(idx, check_empty_slot, module);
-       if (idx < 0)
-               err = -ENODEV;
-       else if (idx < snd_ecards_limit) {
-               if (test_bit(idx, snd_cards_lock))
-                       err = -EBUSY;   /* invalid */
-       } else if (idx >= SNDRV_CARDS)
-               err = -ENODEV;
+       scoped_guard(mutex, &snd_card_mutex) {
+               if (idx < 0) /* first check the matching module-name slot */
+                       idx = get_slot_from_bitmask(idx, module_slot_match, module);
+               if (idx < 0) /* if not matched, assign an empty slot */
+                       idx = get_slot_from_bitmask(idx, check_empty_slot, module);
+               if (idx < 0)
+                       err = -ENODEV;
+               else if (idx < snd_ecards_limit) {
+                       if (test_bit(idx, snd_cards_lock))
+                               err = -EBUSY;   /* invalid */
+               } else if (idx >= SNDRV_CARDS)
+                       err = -ENODEV;
+               if (!err) {
+                       set_bit(idx, snd_cards_lock);           /* lock it */
+                       if (idx >= snd_ecards_limit)
+                               snd_ecards_limit = idx + 1; /* increase the limit */
+               }
+       }
        if (err < 0) {
-               mutex_unlock(&snd_card_mutex);
                dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
-                        idx, snd_ecards_limit - 1, err);
+                       idx, snd_ecards_limit - 1, err);
                if (!card->managed)
                        kfree(card); /* manually free here, as no destructor called */
                return err;
        }
-       set_bit(idx, snd_cards_lock);           /* lock it */
-       if (idx >= snd_ecards_limit)
-               snd_ecards_limit = idx + 1; /* increase the limit */
-       mutex_unlock(&snd_card_mutex);
        card->dev = parent;
        card->number = idx;
 #ifdef MODULE
@@ -386,11 +387,10 @@ struct snd_card *snd_card_ref(int idx)
 {
        struct snd_card *card;
 
-       mutex_lock(&snd_card_mutex);
+       guard(mutex)(&snd_card_mutex);
        card = snd_cards[idx];
        if (card)
                get_device(&card->card_dev);
-       mutex_unlock(&snd_card_mutex);
        return card;
 }
 EXPORT_SYMBOL_GPL(snd_card_ref);
@@ -398,12 +398,8 @@ EXPORT_SYMBOL_GPL(snd_card_ref);
 /* return non-zero if a card is already locked */
 int snd_card_locked(int card)
 {
-       int locked;
-
-       mutex_lock(&snd_card_mutex);
-       locked = test_bit(card, snd_cards_lock);
-       mutex_unlock(&snd_card_mutex);
-       return locked;
+       guard(mutex)(&snd_card_mutex);
+       return test_bit(card, snd_cards_lock);
 }
 
 static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
@@ -427,15 +423,15 @@ static int snd_disconnect_release(struct inode *inode, struct file *file)
 {
        struct snd_monitor_file *df = NULL, *_df;
 
-       spin_lock(&shutdown_lock);
-       list_for_each_entry(_df, &shutdown_files, shutdown_list) {
-               if (_df->file == file) {
-                       df = _df;
-                       list_del_init(&df->shutdown_list);
-                       break;
+       scoped_guard(spinlock, &shutdown_lock) {
+               list_for_each_entry(_df, &shutdown_files, shutdown_list) {
+                       if (_df->file == file) {
+                               df = _df;
+                               list_del_init(&df->shutdown_list);
+                               break;
+                       }
                }
        }
-       spin_unlock(&shutdown_lock);
 
        if (likely(df)) {
                if ((file->f_flags & FASYNC) && df->disconnected_f_op->fasync)
@@ -501,27 +497,24 @@ void snd_card_disconnect(struct snd_card *card)
        if (!card)
                return;
 
-       spin_lock(&card->files_lock);
-       if (card->shutdown) {
-               spin_unlock(&card->files_lock);
-               return;
-       }
-       card->shutdown = 1;
+       scoped_guard(spinlock, &card->files_lock) {
+               if (card->shutdown)
+                       return;
+               card->shutdown = 1;
 
-       /* replace file->f_op with special dummy operations */
-       list_for_each_entry(mfile, &card->files_list, list) {
-               /* it's critical part, use endless loop */
-               /* we have no room to fail */
-               mfile->disconnected_f_op = mfile->file->f_op;
+               /* replace file->f_op with special dummy operations */
+               list_for_each_entry(mfile, &card->files_list, list) {
+                       /* it's critical part, use endless loop */
+                       /* we have no room to fail */
+                       mfile->disconnected_f_op = mfile->file->f_op;
 
-               spin_lock(&shutdown_lock);
-               list_add(&mfile->shutdown_list, &shutdown_files);
-               spin_unlock(&shutdown_lock);
+                       scoped_guard(spinlock, &shutdown_lock)
+                               list_add(&mfile->shutdown_list, &shutdown_files);
 
-               mfile->file->f_op = &snd_shutdown_f_ops;
-               fops_get(mfile->file->f_op);
+                       mfile->file->f_op = &snd_shutdown_f_ops;
+                       fops_get(mfile->file->f_op);
+               }
        }
-       spin_unlock(&card->files_lock); 
 
        /* notify all connected devices about disconnection */
        /* at this point, they cannot respond to any calls except release() */
@@ -544,10 +537,10 @@ void snd_card_disconnect(struct snd_card *card)
        }
 
        /* disable fops (user space) operations for ALSA API */
-       mutex_lock(&snd_card_mutex);
-       snd_cards[card->number] = NULL;
-       clear_bit(card->number, snd_cards_lock);
-       mutex_unlock(&snd_card_mutex);
+       scoped_guard(mutex, &snd_card_mutex) {
+               snd_cards[card->number] = NULL;
+               clear_bit(card->number, snd_cards_lock);
+       }
 
 #ifdef CONFIG_PM
        wake_up(&card->power_sleep);
@@ -569,11 +562,10 @@ void snd_card_disconnect_sync(struct snd_card *card)
 {
        snd_card_disconnect(card);
 
-       spin_lock_irq(&card->files_lock);
+       guard(spinlock_irq)(&card->files_lock);
        wait_event_lock_irq(card->remove_sleep,
                            list_empty(&card->files_list),
                            card->files_lock);
-       spin_unlock_irq(&card->files_lock);
 }
 EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
 
@@ -767,9 +759,8 @@ void snd_card_set_id(struct snd_card *card, const char *nid)
        /* check if user specified own card->id */
        if (card->id[0] != '\0')
                return;
-       mutex_lock(&snd_card_mutex);
+       guard(mutex)(&snd_card_mutex);
        snd_card_set_id_no_lock(card, nid, nid);
-       mutex_unlock(&snd_card_mutex);
 }
 EXPORT_SYMBOL(snd_card_set_id);
 
@@ -797,14 +788,11 @@ static ssize_t id_store(struct device *dev, struct device_attribute *attr,
        }
        memcpy(buf1, buf, copy);
        buf1[copy] = '\0';
-       mutex_lock(&snd_card_mutex);
-       if (!card_id_ok(NULL, buf1)) {
-               mutex_unlock(&snd_card_mutex);
+       guard(mutex)(&snd_card_mutex);
+       if (!card_id_ok(NULL, buf1))
                return -EEXIST;
-       }
        strcpy(card->id, buf1);
        snd_info_card_id_change(card);
-       mutex_unlock(&snd_card_mutex);
 
        return count;
 }
@@ -897,26 +885,27 @@ int snd_card_register(struct snd_card *card)
        err = snd_device_register_all(card);
        if (err < 0)
                return err;
-       mutex_lock(&snd_card_mutex);
-       if (snd_cards[card->number]) {
-               /* already registered */
-               mutex_unlock(&snd_card_mutex);
-               return snd_info_card_register(card); /* register pending info */
-       }
-       if (*card->id) {
-               /* make a unique id name from the given string */
-               char tmpid[sizeof(card->id)];
-               memcpy(tmpid, card->id, sizeof(card->id));
-               snd_card_set_id_no_lock(card, tmpid, tmpid);
-       } else {
-               /* create an id from either shortname or longname */
-               const char *src;
-               src = *card->shortname ? card->shortname : card->longname;
-               snd_card_set_id_no_lock(card, src,
-                                       retrieve_id_from_card_name(src));
+       scoped_guard(mutex, &snd_card_mutex) {
+               if (snd_cards[card->number]) {
+                       /* already registered */
+                       return snd_info_card_register(card); /* register pending info */
+               }
+               if (*card->id) {
+                       /* make a unique id name from the given string */
+                       char tmpid[sizeof(card->id)];
+
+                       memcpy(tmpid, card->id, sizeof(card->id));
+                       snd_card_set_id_no_lock(card, tmpid, tmpid);
+               } else {
+                       /* create an id from either shortname or longname */
+                       const char *src;
+
+                       src = *card->shortname ? card->shortname : card->longname;
+                       snd_card_set_id_no_lock(card, src,
+                                               retrieve_id_from_card_name(src));
+               }
+               snd_cards[card->number] = card;
        }
-       snd_cards[card->number] = card;
-       mutex_unlock(&snd_card_mutex);
        err = snd_info_card_register(card);
        if (err < 0)
                return err;
@@ -937,7 +926,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
        struct snd_card *card;
 
        for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
-               mutex_lock(&snd_card_mutex);
+               guard(mutex)(&snd_card_mutex);
                card = snd_cards[idx];
                if (card) {
                        count++;
@@ -949,7 +938,6 @@ static void snd_card_info_read(struct snd_info_entry *entry,
                        snd_iprintf(buffer, "                      %s\n",
                                        card->longname);
                }
-               mutex_unlock(&snd_card_mutex);
        }
        if (!count)
                snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -962,13 +950,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
        struct snd_card *card;
 
        for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
-               mutex_lock(&snd_card_mutex);
+               guard(mutex)(&snd_card_mutex);
                card = snd_cards[idx];
                if (card) {
                        count++;
                        snd_iprintf(buffer, "%s\n", card->longname);
                }
-               mutex_unlock(&snd_card_mutex);
        }
        if (!count) {
                snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -985,12 +972,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
        struct snd_card *card;
 
        for (idx = 0; idx < SNDRV_CARDS; idx++) {
-               mutex_lock(&snd_card_mutex);
+               guard(mutex)(&snd_card_mutex);
                card = snd_cards[idx];
                if (card)
                        snd_iprintf(buffer, "%2i %s\n",
                                    idx, card->module->name);
-               mutex_unlock(&snd_card_mutex);
        }
 }
 #endif
@@ -1072,15 +1058,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
        mfile->file = file;
        mfile->disconnected_f_op = NULL;
        INIT_LIST_HEAD(&mfile->shutdown_list);
-       spin_lock(&card->files_lock);
+       guard(spinlock)(&card->files_lock);
        if (card->shutdown) {
-               spin_unlock(&card->files_lock);
                kfree(mfile);
                return -ENODEV;
        }
        list_add(&mfile->list, &card->files_list);
        get_device(&card->card_dev);
-       spin_unlock(&card->files_lock);
        return 0;
 }
 EXPORT_SYMBOL(snd_card_file_add);
@@ -1102,22 +1086,21 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
 {
        struct snd_monitor_file *mfile, *found = NULL;
 
-       spin_lock(&card->files_lock);
-       list_for_each_entry(mfile, &card->files_list, list) {
-               if (mfile->file == file) {
-                       list_del(&mfile->list);
-                       spin_lock(&shutdown_lock);
-                       list_del(&mfile->shutdown_list);
-                       spin_unlock(&shutdown_lock);
-                       if (mfile->disconnected_f_op)
-                               fops_put(mfile->disconnected_f_op);
-                       found = mfile;
-                       break;
+       scoped_guard(spinlock, &card->files_lock) {
+               list_for_each_entry(mfile, &card->files_list, list) {
+                       if (mfile->file == file) {
+                               list_del(&mfile->list);
+                               scoped_guard(spinlock, &shutdown_lock)
+                                       list_del(&mfile->shutdown_list);
+                               if (mfile->disconnected_f_op)
+                                       fops_put(mfile->disconnected_f_op);
+                               found = mfile;
+                               break;
+                       }
                }
+               if (list_empty(&card->files_list))
+                       wake_up_all(&card->remove_sleep);
        }
-       if (list_empty(&card->files_list))
-               wake_up_all(&card->remove_sleep);
-       spin_unlock(&card->files_lock);
        if (!found) {
                dev_err(card->dev, "card file remove problem (%p)\n", file);
                return -ENOENT;
index e0f034e7275cd569fa9dee70f7bf4d2dbe882714..e08b2c4fbd1a577380d31781d28b222b404c5c2c 100644 (file)
@@ -42,11 +42,9 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
 #ifdef CONFIG_SND_JACK_INPUT_DEV
        struct snd_jack *jack = device->device_data;
 
-       mutex_lock(&jack->input_dev_lock);
-       if (!jack->input_dev) {
-               mutex_unlock(&jack->input_dev_lock);
+       guard(mutex)(&jack->input_dev_lock);
+       if (!jack->input_dev)
                return 0;
-       }
 
        /* If the input device is registered with the input subsystem
         * then we need to use a different deallocator. */
@@ -55,7 +53,6 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
        else
                input_free_device(jack->input_dev);
        jack->input_dev = NULL;
-       mutex_unlock(&jack->input_dev_lock);
 #endif /* CONFIG_SND_JACK_INPUT_DEV */
        return 0;
 }
@@ -92,11 +89,9 @@ static int snd_jack_dev_register(struct snd_device *device)
        snprintf(jack->name, sizeof(jack->name), "%s %s",
                 card->shortname, jack->id);
 
-       mutex_lock(&jack->input_dev_lock);
-       if (!jack->input_dev) {
-               mutex_unlock(&jack->input_dev_lock);
+       guard(mutex)(&jack->input_dev_lock);
+       if (!jack->input_dev)
                return 0;
-       }
 
        jack->input_dev->name = jack->name;
 
@@ -121,7 +116,6 @@ static int snd_jack_dev_register(struct snd_device *device)
        if (err == 0)
                jack->registered = 1;
 
-       mutex_unlock(&jack->input_dev_lock);
        return err;
 }
 #endif /* CONFIG_SND_JACK_INPUT_DEV */
@@ -586,14 +580,9 @@ EXPORT_SYMBOL(snd_jack_new);
 void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
 {
        WARN_ON(jack->registered);
-       mutex_lock(&jack->input_dev_lock);
-       if (!jack->input_dev) {
-               mutex_unlock(&jack->input_dev_lock);
-               return;
-       }
-
-       jack->input_dev->dev.parent = parent;
-       mutex_unlock(&jack->input_dev_lock);
+       guard(mutex)(&jack->input_dev_lock);
+       if (jack->input_dev)
+               jack->input_dev->dev.parent = parent;
 }
 EXPORT_SYMBOL(snd_jack_set_parent);
 
index dae2da3808351bf2178c3b0cda484479014ff6ea..6a0508093ea6889f888a810641d7ae21b71c2ee0 100644 (file)
@@ -130,13 +130,12 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
 
        if (mixer == NULL)
                return -EIO;
-       mutex_lock(&mixer->reg_mutex);
+       guard(mutex)(&mixer->reg_mutex);
        for (chn = 0; chn < 31; chn++) {
                pslot = &mixer->slots[chn];
                if (pslot->put_volume || pslot->put_recsrc)
                        result |= 1 << chn;
        }
-       mutex_unlock(&mixer->reg_mutex);
        return result;
 }
 
@@ -148,13 +147,12 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
 
        if (mixer == NULL)
                return -EIO;
-       mutex_lock(&mixer->reg_mutex);
+       guard(mutex)(&mixer->reg_mutex);
        for (chn = 0; chn < 31; chn++) {
                pslot = &mixer->slots[chn];
                if (pslot->put_volume && pslot->stereo)
                        result |= 1 << chn;
        }
-       mutex_unlock(&mixer->reg_mutex);
        return result;
 }
 
@@ -165,7 +163,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
 
        if (mixer == NULL)
                return -EIO;
-       mutex_lock(&mixer->reg_mutex);
+       guard(mutex)(&mixer->reg_mutex);
        if (mixer->put_recsrc && mixer->get_recsrc) {   /* exclusive */
                result = mixer->mask_recsrc;
        } else {
@@ -177,7 +175,6 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
                                result |= 1 << chn;
                }
        }
-       mutex_unlock(&mixer->reg_mutex);
        return result;
 }
 
@@ -188,12 +185,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
 
        if (mixer == NULL)
                return -EIO;
-       mutex_lock(&mixer->reg_mutex);
+       guard(mutex)(&mixer->reg_mutex);
        if (mixer->put_recsrc && mixer->get_recsrc) {   /* exclusive */
                unsigned int index;
                result = mixer->get_recsrc(fmixer, &index);
                if (result < 0)
-                       goto unlock;
+                       return result;
                result = 1 << index;
        } else {
                struct snd_mixer_oss_slot *pslot;
@@ -209,8 +206,6 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
                }
        }
        mixer->oss_recsrc = result;
- unlock:
-       mutex_unlock(&mixer->reg_mutex);
        return result;
 }
 
@@ -224,7 +219,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
 
        if (mixer == NULL)
                return -EIO;
-       mutex_lock(&mixer->reg_mutex);
+       guard(mutex)(&mixer->reg_mutex);
        if (mixer->get_recsrc && mixer->put_recsrc) {   /* exclusive input */
                if (recsrc & ~mixer->oss_recsrc)
                        recsrc &= ~mixer->oss_recsrc;
@@ -250,7 +245,6 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
                        }
                }
        }
-       mutex_unlock(&mixer->reg_mutex);
        return result;
 }
 
@@ -262,7 +256,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
 
        if (mixer == NULL || slot > 30)
                return -EIO;
-       mutex_lock(&mixer->reg_mutex);
+       guard(mutex)(&mixer->reg_mutex);
        pslot = &mixer->slots[slot];
        left = pslot->volume[0];
        right = pslot->volume[1];
@@ -270,21 +264,15 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
                result = pslot->get_volume(fmixer, pslot, &left, &right);
        if (!pslot->stereo)
                right = left;
-       if (snd_BUG_ON(left < 0 || left > 100)) {
-               result = -EIO;
-               goto unlock;
-       }
-       if (snd_BUG_ON(right < 0 || right > 100)) {
-               result = -EIO;
-               goto unlock;
-       }
+       if (snd_BUG_ON(left < 0 || left > 100))
+               return -EIO;
+       if (snd_BUG_ON(right < 0 || right > 100))
+               return -EIO;
        if (result >= 0) {
                pslot->volume[0] = left;
                pslot->volume[1] = right;
                result = (left & 0xff) | ((right & 0xff) << 8);
        }
- unlock:
-       mutex_unlock(&mixer->reg_mutex);
        return result;
 }
 
@@ -297,7 +285,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
 
        if (mixer == NULL || slot > 30)
                return -EIO;
-       mutex_lock(&mixer->reg_mutex);
+       guard(mutex)(&mixer->reg_mutex);
        pslot = &mixer->slots[slot];
        if (left > 100)
                left = 100;
@@ -308,12 +296,10 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
        if (pslot->put_volume)
                result = pslot->put_volume(fmixer, pslot, left, right);
        if (result < 0)
-               goto unlock;
+               return result;
        pslot->volume[0] = left;
        pslot->volume[1] = right;
        result = (left & 0xff) | ((right & 0xff) << 8);
- unlock:
-       mutex_unlock(&mixer->reg_mutex);
        return result;
 }
 
@@ -532,37 +518,31 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
                                          unsigned int numid,
                                          int *left, int *right)
 {
-       struct snd_ctl_elem_info *uinfo;
-       struct snd_ctl_elem_value *uctl;
+       struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+       struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
        struct snd_kcontrol *kctl;
        struct snd_card *card = fmixer->card;
 
        if (numid == ID_UNKNOWN)
                return;
-       down_read(&card->controls_rwsem);
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_ctl_find_numid_locked(card, numid);
-       if (!kctl) {
-               up_read(&card->controls_rwsem);
+       if (!kctl)
                return;
-       }
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL)
-               goto __unalloc;
+               return;
        if (kctl->info(kctl, uinfo))
-               goto __unalloc;
+               return;
        if (kctl->get(kctl, uctl))
-               goto __unalloc;
+               return;
        if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
            uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
-               goto __unalloc;
+               return;
        *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
        if (uinfo->count > 1)
                *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
-      __unalloc:
-       up_read(&card->controls_rwsem);
-       kfree(uctl);
-       kfree(uinfo);
 }
 
 static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
@@ -571,27 +551,25 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
                                         int *left, int *right,
                                         int route)
 {
-       struct snd_ctl_elem_info *uinfo;
-       struct snd_ctl_elem_value *uctl;
+       struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+       struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
        struct snd_kcontrol *kctl;
        struct snd_card *card = fmixer->card;
 
        if (numid == ID_UNKNOWN)
                return;
-       down_read(&card->controls_rwsem);
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_ctl_find_numid_locked(card, numid);
-       if (!kctl) {
-               up_read(&card->controls_rwsem);
+       if (!kctl)
                return;
-       }
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL)
-               goto __unalloc;
+               return;
        if (kctl->info(kctl, uinfo))
-               goto __unalloc;
+               return;
        if (kctl->get(kctl, uctl))
-               goto __unalloc;
+               return;
        if (!uctl->value.integer.value[0]) {
                *left = 0;
                if (uinfo->count == 1)
@@ -599,10 +577,6 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
        }
        if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
                *right = 0;
-      __unalloc:
-       up_read(&card->controls_rwsem);
-       kfree(uctl);
-       kfree(uinfo);
 }
 
 static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
@@ -636,41 +610,35 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
                                          unsigned int numid,
                                          int left, int right)
 {
-       struct snd_ctl_elem_info *uinfo;
-       struct snd_ctl_elem_value *uctl;
+       struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+       struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
        struct snd_kcontrol *kctl;
        struct snd_card *card = fmixer->card;
        int res;
 
        if (numid == ID_UNKNOWN)
                return;
-       down_read(&card->controls_rwsem);
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_ctl_find_numid_locked(card, numid);
-       if (!kctl) {
-               up_read(&card->controls_rwsem);
+       if (!kctl)
                return;
-       }
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL)
-               goto __unalloc;
+               return;
        if (kctl->info(kctl, uinfo))
-               goto __unalloc;
+               return;
        if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
            uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
-               goto __unalloc;
+               return;
        uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
        if (uinfo->count > 1)
                uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
        res = kctl->put(kctl, uctl);
        if (res < 0)
-               goto __unalloc;
+               return;
        if (res > 0)
                snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
-      __unalloc:
-       up_read(&card->controls_rwsem);
-       kfree(uctl);
-       kfree(uinfo);
 }
 
 static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
@@ -679,26 +647,24 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
                                         int left, int right,
                                         int route)
 {
-       struct snd_ctl_elem_info *uinfo;
-       struct snd_ctl_elem_value *uctl;
+       struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+       struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
        struct snd_kcontrol *kctl;
        struct snd_card *card = fmixer->card;
        int res;
 
        if (numid == ID_UNKNOWN)
                return;
-       down_read(&card->controls_rwsem);
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_ctl_find_numid_locked(card, numid);
-       if (!kctl) {
-               up_read(&card->controls_rwsem);
+       if (!kctl)
                return;
-       }
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL)
-               goto __unalloc;
+               return;
        if (kctl->info(kctl, uinfo))
-               goto __unalloc;
+               return;
        if (uinfo->count > 1) {
                uctl->value.integer.value[0] = left > 0 ? 1 : 0;
                uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
@@ -711,13 +677,9 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
        }
        res = kctl->put(kctl, uctl);
        if (res < 0)
-               goto __unalloc;
+               return;
        if (res > 0)
                snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
-      __unalloc:
-       up_read(&card->controls_rwsem);
-       kfree(uctl);
-       kfree(uinfo);
 }
 
 static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
@@ -822,28 +784,24 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        struct snd_kcontrol *kctl;
        struct snd_mixer_oss_slot *pslot;
        struct slot *slot;
-       struct snd_ctl_elem_info *uinfo;
-       struct snd_ctl_elem_value *uctl;
+       struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+       struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
        int err, idx;
        
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
-       if (uinfo == NULL || uctl == NULL) {
-               err = -ENOMEM;
-               goto __free_only;
-       }
-       down_read(&card->controls_rwsem);
+       if (uinfo == NULL || uctl == NULL)
+               return -ENOMEM;
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
-       if (! kctl) {
-               err = -ENOENT;
-               goto __unlock;
-       }
+       if (!kctl)
+               return -ENOENT;
        err = kctl->info(kctl, uinfo);
        if (err < 0)
-               goto __unlock;
+               return err;
        err = kctl->get(kctl, uctl);
        if (err < 0)
-               goto __unlock;
+               return err;
        for (idx = 0; idx < 32; idx++) {
                if (!(mixer->mask_recsrc & (1 << idx)))
                        continue;
@@ -858,13 +816,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
                        break;
                }
        }
-       err = 0;
-      __unlock:
-       up_read(&card->controls_rwsem);
-      __free_only:
-       kfree(uctl);
-       kfree(uinfo);
-       return err;
+       return 0;
 }
 
 static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
@@ -874,26 +826,22 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        struct snd_kcontrol *kctl;
        struct snd_mixer_oss_slot *pslot;
        struct slot *slot = NULL;
-       struct snd_ctl_elem_info *uinfo;
-       struct snd_ctl_elem_value *uctl;
+       struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+       struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
        int err;
        unsigned int idx;
 
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
-       if (uinfo == NULL || uctl == NULL) {
-               err = -ENOMEM;
-               goto __free_only;
-       }
-       down_read(&card->controls_rwsem);
+       if (uinfo == NULL || uctl == NULL)
+               return -ENOMEM;
+       guard(rwsem_read)(&card->controls_rwsem);
        kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
-       if (! kctl) {
-               err = -ENOENT;
-               goto __unlock;
-       }
+       if (!kctl)
+               return -ENOENT;
        err = kctl->info(kctl, uinfo);
        if (err < 0)
-               goto __unlock;
+               return err;
        for (idx = 0; idx < 32; idx++) {
                if (!(mixer->mask_recsrc & (1 << idx)))
                        continue;
@@ -907,20 +855,14 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
                        break;
                slot = NULL;
        }
-       if (! slot)
-               goto __unlock;
+       if (!slot)
+               return 0;
        for (idx = 0; idx < uinfo->count; idx++)
                uctl->value.enumerated.item[idx] = slot->capture_item;
        err = kctl->put(kctl, uctl);
        if (err > 0)
                snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
-       err = 0;
-      __unlock:
-       up_read(&card->controls_rwsem);
-      __free_only:
-       kfree(uctl);
-       kfree(uinfo);
-       return err;
+       return 0;
 }
 
 struct snd_mixer_oss_assign_table {
@@ -931,34 +873,26 @@ struct snd_mixer_oss_assign_table {
 
 static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
 {
-       struct snd_ctl_elem_info *info;
+       struct snd_ctl_elem_info *info __free(kfree) = NULL;
        struct snd_kcontrol *kcontrol;
        struct snd_card *card = mixer->card;
        int err;
 
-       down_read(&card->controls_rwsem);
-       kcontrol = snd_mixer_oss_test_id(mixer, name, index);
-       if (kcontrol == NULL) {
-               up_read(&card->controls_rwsem);
-               return 0;
-       }
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (! info) {
-               up_read(&card->controls_rwsem);
-               return -ENOMEM;
-       }
-       err = kcontrol->info(kcontrol, info);
-       if (err < 0) {
-               up_read(&card->controls_rwsem);
-               kfree(info);
-               return err;
+       scoped_guard(rwsem_read, &card->controls_rwsem) {
+               kcontrol = snd_mixer_oss_test_id(mixer, name, index);
+               if (kcontrol == NULL)
+                       return 0;
+               info = kmalloc(sizeof(*info), GFP_KERNEL);
+               if (!info)
+                       return -ENOMEM;
+               err = kcontrol->info(kcontrol, info);
+               if (err < 0)
+                       return err;
+               slot->numid[item] = kcontrol->id.numid;
        }
-       slot->numid[item] = kcontrol->id.numid;
-       up_read(&card->controls_rwsem);
        if (info->count > slot->channels)
                slot->channels = info->count;
        slot->present |= 1 << item;
-       kfree(info);
        return 0;
 }
 
@@ -1068,24 +1002,19 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
        memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
        if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
                return 0;
-       down_read(&mixer->card->controls_rwsem);
+       guard(rwsem_read)(&mixer->card->controls_rwsem);
        kctl = NULL;
        if (!ptr->index)
                kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
        if (kctl) {
-               struct snd_ctl_elem_info *uinfo;
+               struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
 
                uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
-               if (! uinfo) {
-                       up_read(&mixer->card->controls_rwsem);
+               if (!uinfo)
                        return -ENOMEM;
-               }
                        
-               if (kctl->info(kctl, uinfo)) {
-                       up_read(&mixer->card->controls_rwsem);
-                       kfree(uinfo);
+               if (kctl->info(kctl, uinfo))
                        return 0;
-               }
                strcpy(str, ptr->name);
                if (!strcmp(str, "Master"))
                        strcpy(str, "Mix");
@@ -1097,20 +1026,15 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
                } else {
                        for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
                                uinfo->value.enumerated.item = slot.capture_item;
-                               if (kctl->info(kctl, uinfo)) {
-                                       up_read(&mixer->card->controls_rwsem);
-                                       kfree(uinfo);
+                               if (kctl->info(kctl, uinfo))
                                        return 0;
-                               }
                                if (!strcmp(uinfo->value.enumerated.name, str)) {
                                        slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
                                        break;
                                }
                        }
                }
-               kfree(uinfo);
        }
-       up_read(&mixer->card->controls_rwsem);
        if (slot.present != 0) {
                pslot = kmalloc(sizeof(slot), GFP_KERNEL);
                if (! pslot)
@@ -1183,7 +1107,7 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
        struct snd_mixer_oss *mixer = entry->private_data;
        int i;
 
-       mutex_lock(&mixer->reg_mutex);
+       guard(mutex)(&mixer->reg_mutex);
        for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
                struct slot *p;
 
@@ -1198,7 +1122,6 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
                else
                        snd_iprintf(buffer, "\"\" 0\n");
        }
-       mutex_unlock(&mixer->reg_mutex);
 }
 
 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
@@ -1225,9 +1148,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                cptr = snd_info_get_str(str, cptr, sizeof(str));
                if (! *str) {
                        /* remove the entry */
-                       mutex_lock(&mixer->reg_mutex);
-                       mixer_slot_clear(&mixer->slots[ch]);
-                       mutex_unlock(&mixer->reg_mutex);
+                       scoped_guard(mutex, &mixer->reg_mutex)
+                               mixer_slot_clear(&mixer->slots[ch]);
                        continue;
                }
                snd_info_get_str(idxstr, cptr, sizeof(idxstr));
@@ -1236,28 +1158,27 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                        pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
                        continue;
                }
-               mutex_lock(&mixer->reg_mutex);
-               slot = (struct slot *)mixer->slots[ch].private_data;
-               if (slot && slot->assigned &&
-                   slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
-                       /* not changed */
-                       goto __unlock;
-               tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
-               if (!tbl)
-                       goto __unlock;
-               tbl->oss_id = ch;
-               tbl->name = kstrdup(str, GFP_KERNEL);
-               if (! tbl->name) {
-                       kfree(tbl);
-                       goto __unlock;
-               }
-               tbl->index = idx;
-               if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
-                       kfree(tbl->name);
-                       kfree(tbl);
+               scoped_guard(mutex, &mixer->reg_mutex) {
+                       slot = (struct slot *)mixer->slots[ch].private_data;
+                       if (slot && slot->assigned &&
+                           slot->assigned->index == idx && !strcmp(slot->assigned->name, str))
+                               /* not changed */
+                               break;
+                       tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
+                       if (!tbl)
+                               break;
+                       tbl->oss_id = ch;
+                       tbl->name = kstrdup(str, GFP_KERNEL);
+                       if (!tbl->name) {
+                               kfree(tbl);
+                               break;
+                       }
+                       tbl->index = idx;
+                       if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
+                               kfree(tbl->name);
+                               kfree(tbl);
+                       }
                }
-       __unlock:
-               mutex_unlock(&mixer->reg_mutex);
        }
 }
 
index 728c211142d145df7143856d3a0ea1912f173760..7386982cf40edcbaf6c5832301d0556f90a1e2c0 100644 (file)
@@ -377,7 +377,7 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
                                 snd_pcm_hw_param_t var, unsigned int best,
                                 int *dir)
 {
-       struct snd_pcm_hw_params *save = NULL;
+       struct snd_pcm_hw_params *save __free(kfree) = NULL;
        int v;
        unsigned int saved_min;
        int last = 0;
@@ -404,38 +404,30 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
        saved_min = min;
        min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
        if (min >= 0) {
-               struct snd_pcm_hw_params *params1;
+               struct snd_pcm_hw_params *params1 __free(kfree) = NULL;
                if (max < 0)
                        goto _end;
                if ((unsigned int)min == saved_min && mindir == valdir)
                        goto _end;
                params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
-               if (params1 == NULL) {
-                       kfree(save);
+               if (params1 == NULL)
                        return -ENOMEM;
-               }
                *params1 = *save;
                max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
-               if (max < 0) {
-                       kfree(params1);
+               if (max < 0)
                        goto _end;
-               }
                if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
                        *params = *params1;
                        last = 1;
                }
-               kfree(params1);
        } else {
                *params = *save;
                max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
-               if (max < 0) {
-                       kfree(save);
+               if (max < 0)
                        return max;
-               }
                last = 1;
        }
  _end:
-       kfree(save);
        if (last)
                v = snd_pcm_hw_param_last(pcm, params, var, dir);
        else
@@ -789,7 +781,7 @@ static int choose_rate(struct snd_pcm_substream *substream,
                       struct snd_pcm_hw_params *params, unsigned int best_rate)
 {
        const struct snd_interval *it;
-       struct snd_pcm_hw_params *save;
+       struct snd_pcm_hw_params *save __free(kfree) = NULL;
        unsigned int rate, prev;
 
        save = kmalloc(sizeof(*save), GFP_KERNEL);
@@ -808,10 +800,8 @@ static int choose_rate(struct snd_pcm_substream *substream,
                        ret = snd_pcm_hw_param_set(substream, params,
                                                   SNDRV_PCM_HW_PARAM_RATE,
                                                   rate, 0);
-                       if (ret == (int)rate) {
-                               kfree(save);
+                       if (ret == (int)rate)
                                return rate;
-                       }
                        *params = *save;
                }
                prev = rate;
@@ -821,7 +811,6 @@ static int choose_rate(struct snd_pcm_substream *substream,
        }
 
        /* not found, use the nearest rate */
-       kfree(save);
        return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
 }
 
@@ -1634,9 +1623,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
                        break;
                result = 0;
                set_current_state(TASK_INTERRUPTIBLE);
-               snd_pcm_stream_lock_irq(substream);
-               state = runtime->state;
-               snd_pcm_stream_unlock_irq(substream);
+               scoped_guard(pcm_stream_lock_irq, substream)
+                       state = runtime->state;
                if (state != SNDRV_PCM_STATE_RUNNING) {
                        set_current_state(TASK_RUNNING);
                        break;
@@ -1847,7 +1835,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
        struct snd_pcm_substream *substream;
        int err;
        int direct;
-       struct snd_pcm_hw_params *params;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
        unsigned int formats = 0;
        const struct snd_mask *format_mask;
        int fmt;
@@ -1873,7 +1861,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
        _snd_pcm_hw_params_any(params);
        err = snd_pcm_hw_refine(substream, params);
        if (err < 0)
-               goto error;
+               return err;
        format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
        for (fmt = 0; fmt < 32; ++fmt) {
                if (snd_mask_test(format_mask, fmt)) {
@@ -1883,9 +1871,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
                }
        }
 
- error:
-       kfree(params);
-       return err < 0 ? err : formats;
+       return formats;
 }
 
 static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
@@ -2347,7 +2333,7 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
 {
        struct snd_pcm_oss_setup *setup;
 
-       mutex_lock(&pcm->streams[stream].oss.setup_mutex);
+       guard(mutex)(&pcm->streams[stream].oss.setup_mutex);
        do {
                for (setup = pcm->streams[stream].oss.setup_list; setup;
                     setup = setup->next) {
@@ -2358,7 +2344,6 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
  out:
        if (setup)
                *rsetup = *setup;
-       mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
 }
 
 static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
@@ -2853,23 +2838,23 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
        if (psubstream != NULL) {
                struct snd_pcm_runtime *runtime = psubstream->runtime;
                poll_wait(file, &runtime->sleep, wait);
-               snd_pcm_stream_lock_irq(psubstream);
-               if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
-                   (runtime->state != SNDRV_PCM_STATE_RUNNING ||
-                    snd_pcm_oss_playback_ready(psubstream)))
-                       mask |= EPOLLOUT | EPOLLWRNORM;
-               snd_pcm_stream_unlock_irq(psubstream);
+               scoped_guard(pcm_stream_lock_irq, psubstream) {
+                       if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
+                           (runtime->state != SNDRV_PCM_STATE_RUNNING ||
+                            snd_pcm_oss_playback_ready(psubstream)))
+                               mask |= EPOLLOUT | EPOLLWRNORM;
+               }
        }
        if (csubstream != NULL) {
                struct snd_pcm_runtime *runtime = csubstream->runtime;
                snd_pcm_state_t ostate;
                poll_wait(file, &runtime->sleep, wait);
-               snd_pcm_stream_lock_irq(csubstream);
-               ostate = runtime->state;
-               if (ostate != SNDRV_PCM_STATE_RUNNING ||
-                   snd_pcm_oss_capture_ready(csubstream))
-                       mask |= EPOLLIN | EPOLLRDNORM;
-               snd_pcm_stream_unlock_irq(csubstream);
+               scoped_guard(pcm_stream_lock_irq, csubstream) {
+                       ostate = runtime->state;
+                       if (ostate != SNDRV_PCM_STATE_RUNNING ||
+                           snd_pcm_oss_capture_ready(csubstream))
+                               mask |= EPOLLIN | EPOLLRDNORM;
+               }
                if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
                        struct snd_pcm_oss_file ofile;
                        memset(&ofile, 0, sizeof(ofile));
@@ -2964,7 +2949,7 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
 {
        struct snd_pcm_str *pstr = entry->private_data;
        struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
-       mutex_lock(&pstr->oss.setup_mutex);
+       guard(mutex)(&pstr->oss.setup_mutex);
        while (setup) {
                snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
                            setup->task_name,
@@ -2978,7 +2963,6 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
                            setup->nosilence ? " no-silence" : "");
                setup = setup->next;
        }
-       mutex_unlock(&pstr->oss.setup_mutex);
 }
 
 static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
@@ -3004,12 +2988,11 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
        struct snd_pcm_oss_setup *setup, *setup1, template;
 
        while (!snd_info_get_line(buffer, line, sizeof(line))) {
-               mutex_lock(&pstr->oss.setup_mutex);
+               guard(mutex)(&pstr->oss.setup_mutex);
                memset(&template, 0, sizeof(template));
                ptr = snd_info_get_str(task_name, line, sizeof(task_name));
                if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
                        snd_pcm_oss_proc_free_setup_list(pstr);
-                       mutex_unlock(&pstr->oss.setup_mutex);
                        continue;
                }
                for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
@@ -3049,7 +3032,6 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
                        setup = kmalloc(sizeof(*setup), GFP_KERNEL);
                        if (! setup) {
                                buffer->error = -ENOMEM;
-                               mutex_unlock(&pstr->oss.setup_mutex);
                                return;
                        }
                        if (pstr->oss.setup_list == NULL)
@@ -3063,12 +3045,10 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
                        if (! template.task_name) {
                                kfree(setup);
                                buffer->error = -ENOMEM;
-                               mutex_unlock(&pstr->oss.setup_mutex);
                                return;
                        }
                }
                *setup = template;
-               mutex_unlock(&pstr->oss.setup_mutex);
        }
 }
 
index d0788126cbab10a2ef8daaab9201f366f27d8c63..dc37f3508dc7a04c33d7471293cd9e22ffba66c4 100644 (file)
@@ -91,9 +91,8 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
 
                        if (get_user(device, (int __user *)arg))
                                return -EFAULT;
-                       mutex_lock(&register_mutex);
-                       device = snd_pcm_next(card, device);
-                       mutex_unlock(&register_mutex);
+                       scoped_guard(mutex, &register_mutex)
+                               device = snd_pcm_next(card, device);
                        if (put_user(device, (int __user *)arg))
                                return -EFAULT;
                        return 0;
@@ -106,7 +105,6 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                        struct snd_pcm *pcm;
                        struct snd_pcm_str *pstr;
                        struct snd_pcm_substream *substream;
-                       int err;
 
                        info = (struct snd_pcm_info __user *)arg;
                        if (get_user(device, &info->device))
@@ -118,35 +116,23 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                        stream = array_index_nospec(stream, 2);
                        if (get_user(subdevice, &info->subdevice))
                                return -EFAULT;
-                       mutex_lock(&register_mutex);
+                       guard(mutex)(&register_mutex);
                        pcm = snd_pcm_get(card, device);
-                       if (pcm == NULL) {
-                               err = -ENXIO;
-                               goto _error;
-                       }
+                       if (pcm == NULL)
+                               return -ENXIO;
                        pstr = &pcm->streams[stream];
-                       if (pstr->substream_count == 0) {
-                               err = -ENOENT;
-                               goto _error;
-                       }
-                       if (subdevice >= pstr->substream_count) {
-                               err = -ENXIO;
-                               goto _error;
-                       }
+                       if (pstr->substream_count == 0)
+                               return -ENOENT;
+                       if (subdevice >= pstr->substream_count)
+                               return -ENXIO;
                        for (substream = pstr->substream; substream;
                             substream = substream->next)
                                if (substream->number == (int)subdevice)
                                        break;
-                       if (substream == NULL) {
-                               err = -ENXIO;
-                               goto _error;
-                       }
-                       mutex_lock(&pcm->open_mutex);
-                       err = snd_pcm_info_user(substream, info);
-                       mutex_unlock(&pcm->open_mutex);
-               _error:
-                       mutex_unlock(&register_mutex);
-                       return err;
+                       if (substream == NULL)
+                               return -ENXIO;
+                       guard(mutex)(&pcm->open_mutex);
+                       return snd_pcm_info_user(substream, info);
                }
        case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
                {
@@ -225,9 +211,11 @@ static const char * const snd_pcm_format_names[] = {
  */
 const char *snd_pcm_format_name(snd_pcm_format_t format)
 {
-       if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
+       unsigned int format_num = (__force unsigned int)format;
+
+       if (format_num >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format_num])
                return "Unknown";
-       return snd_pcm_format_names[(__force unsigned int)format];
+       return snd_pcm_format_names[format_num];
 }
 EXPORT_SYMBOL_GPL(snd_pcm_format_name);
 
@@ -340,7 +328,7 @@ static const char *snd_pcm_oss_format_name(int format)
 static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
                                   struct snd_info_buffer *buffer)
 {
-       struct snd_pcm_info *info;
+       struct snd_pcm_info *info __free(kfree) = NULL;
        int err;
 
        if (! substream)
@@ -353,7 +341,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
        err = snd_pcm_info(substream, info);
        if (err < 0) {
                snd_iprintf(buffer, "error %d\n", err);
-               kfree(info);
                return;
        }
        snd_iprintf(buffer, "card: %d\n", info->card);
@@ -367,7 +354,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
        snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
        snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
        snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
-       kfree(info);
 }
 
 static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
@@ -389,15 +375,15 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
        struct snd_pcm_substream *substream = entry->private_data;
        struct snd_pcm_runtime *runtime;
 
-       mutex_lock(&substream->pcm->open_mutex);
+       guard(mutex)(&substream->pcm->open_mutex);
        runtime = substream->runtime;
        if (!runtime) {
                snd_iprintf(buffer, "closed\n");
-               goto unlock;
+               return;
        }
        if (runtime->state == SNDRV_PCM_STATE_OPEN) {
                snd_iprintf(buffer, "no setup\n");
-               goto unlock;
+               return;
        }
        snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
        snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
@@ -416,8 +402,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
                snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
        }
 #endif
- unlock:
-       mutex_unlock(&substream->pcm->open_mutex);
 }
 
 static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
@@ -426,15 +410,15 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
        struct snd_pcm_substream *substream = entry->private_data;
        struct snd_pcm_runtime *runtime;
 
-       mutex_lock(&substream->pcm->open_mutex);
+       guard(mutex)(&substream->pcm->open_mutex);
        runtime = substream->runtime;
        if (!runtime) {
                snd_iprintf(buffer, "closed\n");
-               goto unlock;
+               return;
        }
        if (runtime->state == SNDRV_PCM_STATE_OPEN) {
                snd_iprintf(buffer, "no setup\n");
-               goto unlock;
+               return;
        }
        snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
        snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
@@ -444,8 +428,6 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
        snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
        snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
- unlock:
-       mutex_unlock(&substream->pcm->open_mutex);
 }
 
 static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
@@ -456,17 +438,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
        struct snd_pcm_status64 status;
        int err;
 
-       mutex_lock(&substream->pcm->open_mutex);
+       guard(mutex)(&substream->pcm->open_mutex);
        runtime = substream->runtime;
        if (!runtime) {
                snd_iprintf(buffer, "closed\n");
-               goto unlock;
+               return;
        }
        memset(&status, 0, sizeof(status));
        err = snd_pcm_status64(substream, &status);
        if (err < 0) {
                snd_iprintf(buffer, "error %d\n", err);
-               goto unlock;
+               return;
        }
        snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
        snd_iprintf(buffer, "owner_pid   : %d\n", pid_vnr(substream->pid));
@@ -480,8 +462,6 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "-----\n");
        snd_iprintf(buffer, "hw_ptr      : %ld\n", runtime->status->hw_ptr);
        snd_iprintf(buffer, "appl_ptr    : %ld\n", runtime->control->appl_ptr);
- unlock:
-       mutex_unlock(&substream->pcm->open_mutex);
 }
 
 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
@@ -1009,9 +989,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
        kfree(runtime->hw_constraints.rules);
        /* Avoid concurrent access to runtime via PCM timer interface */
        if (substream->timer) {
-               spin_lock_irq(&substream->timer->lock);
-               substream->runtime = NULL;
-               spin_unlock_irq(&substream->timer->lock);
+               scoped_guard(spinlock_irq, &substream->timer->lock)
+                       substream->runtime = NULL;
        } else {
                substream->runtime = NULL;
        }
@@ -1068,10 +1047,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
                return -ENXIO;
        pcm = device->device_data;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        err = snd_pcm_add(pcm);
        if (err)
-               goto unlock;
+               return err;
        for (cidx = 0; cidx < 2; cidx++) {
                int devtype = -1;
                if (pcm->streams[cidx].substream == NULL)
@@ -1090,7 +1069,7 @@ static int snd_pcm_dev_register(struct snd_device *device)
                                          pcm->streams[cidx].dev);
                if (err < 0) {
                        list_del_init(&pcm->list);
-                       goto unlock;
+                       return err;
                }
 
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -1098,9 +1077,6 @@ static int snd_pcm_dev_register(struct snd_device *device)
        }
 
        pcm_call_notify(pcm, n_register);
-
- unlock:
-       mutex_unlock(&register_mutex);
        return err;
 }
 
@@ -1110,8 +1086,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
        struct snd_pcm_substream *substream;
        int cidx;
 
-       mutex_lock(&register_mutex);
-       mutex_lock(&pcm->open_mutex);
+       guard(mutex)(&register_mutex);
+       guard(mutex)(&pcm->open_mutex);
        wake_up(&pcm->open_wait);
        list_del_init(&pcm->list);
 
@@ -1138,8 +1114,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
                        snd_unregister_device(pcm->streams[cidx].dev);
                free_chmap(&pcm->streams[cidx]);
        }
-       mutex_unlock(&pcm->open_mutex);
-       mutex_unlock(&register_mutex);
        return 0;
 }
 
@@ -1164,7 +1138,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
                       !notify->n_unregister ||
                       !notify->n_disconnect))
                return -EINVAL;
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        if (nfree) {
                list_del(&notify->list);
                list_for_each_entry(pcm, &snd_pcm_devices, list)
@@ -1174,7 +1148,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
                list_for_each_entry(pcm, &snd_pcm_devices, list)
                        notify->n_register(pcm);
        }
-       mutex_unlock(&register_mutex);
        return 0;
 }
 EXPORT_SYMBOL(snd_pcm_notify);
@@ -1190,7 +1163,7 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
 {
        struct snd_pcm *pcm;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
                snd_iprintf(buffer, "%02i-%02i: %s : %s",
                            pcm->card->number, pcm->device, pcm->id, pcm->name);
@@ -1202,7 +1175,6 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
                                    pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
                snd_iprintf(buffer, "\n");
        }
-       mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_pcm_proc_entry;
index c96483091f30aa3ff63c3b55bb466b8b63f5df4d..a42ec7f5a1daf0688b758e56d5fcf09959cec8de 100644 (file)
@@ -235,7 +235,7 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
                                          int refine, 
                                          struct snd_pcm_hw_params32 __user *data32)
 {
-       struct snd_pcm_hw_params *data;
+       struct snd_pcm_hw_params *data __free(kfree) = NULL;
        struct snd_pcm_runtime *runtime;
        int err;
 
@@ -248,34 +248,28 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
                return -ENOMEM;
 
        /* only fifo_size (RO from userspace) is different, so just copy all */
-       if (copy_from_user(data, data32, sizeof(*data32))) {
-               err = -EFAULT;
-               goto error;
-       }
+       if (copy_from_user(data, data32, sizeof(*data32)))
+               return -EFAULT;
 
        if (refine) {
                err = snd_pcm_hw_refine(substream, data);
                if (err < 0)
-                       goto error;
+                       return err;
                err = fixup_unreferenced_params(substream, data);
        } else {
                err = snd_pcm_hw_params(substream, data);
        }
        if (err < 0)
-               goto error;
+               return err;
        if (copy_to_user(data32, data, sizeof(*data32)) ||
-           put_user(data->fifo_size, &data32->fifo_size)) {
-               err = -EFAULT;
-               goto error;
-       }
+           put_user(data->fifo_size, &data32->fifo_size))
+               return -EFAULT;
 
        if (! refine) {
                unsigned int new_boundary = recalculate_boundary(runtime);
                if (new_boundary)
                        runtime->boundary = new_boundary;
        }
- error:
-       kfree(data);
        return err;
 }
 
@@ -338,7 +332,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
        compat_caddr_t buf;
        compat_caddr_t __user *bufptr;
        u32 frames;
-       void __user **bufs;
+       void __user **bufs __free(kfree) = NULL;
        int err, ch, i;
 
        if (! substream->runtime)
@@ -360,10 +354,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
                return -ENOMEM;
        for (i = 0; i < ch; i++) {
                u32 ptr;
-               if (get_user(ptr, bufptr)) {
-                       kfree(bufs);
+               if (get_user(ptr, bufptr))
                        return -EFAULT;
-               }
                bufs[i] = compat_ptr(ptr);
                bufptr++;
        }
@@ -373,9 +365,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
                err = snd_pcm_lib_readv(substream, bufs, frames);
        if (err >= 0) {
                if (put_user(err, &data32->result))
-                       err = -EFAULT;
+                       return -EFAULT;
        }
-       kfree(bufs);
        return err;
 }
 
@@ -441,22 +432,22 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
        boundary = recalculate_boundary(runtime);
        if (!boundary)
                boundary = 0x7fffffff;
-       snd_pcm_stream_lock_irq(substream);
-       /* FIXME: we should consider the boundary for the sync from app */
-       if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
-               control->appl_ptr = scontrol.appl_ptr;
-       else
-               scontrol.appl_ptr = control->appl_ptr % boundary;
-       if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
-               control->avail_min = scontrol.avail_min;
-       else
-               scontrol.avail_min = control->avail_min;
-       sstatus.state = status->state;
-       sstatus.hw_ptr = status->hw_ptr % boundary;
-       sstatus.tstamp = status->tstamp;
-       sstatus.suspended_state = status->suspended_state;
-       sstatus.audio_tstamp = status->audio_tstamp;
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               /* FIXME: we should consider the boundary for the sync from app */
+               if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
+                       control->appl_ptr = scontrol.appl_ptr;
+               else
+                       scontrol.appl_ptr = control->appl_ptr % boundary;
+               if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+                       control->avail_min = scontrol.avail_min;
+               else
+                       scontrol.avail_min = control->avail_min;
+               sstatus.state = status->state;
+               sstatus.hw_ptr = status->hw_ptr % boundary;
+               sstatus.tstamp = status->tstamp;
+               sstatus.suspended_state = status->suspended_state;
+               sstatus.audio_tstamp = status->audio_tstamp;
+       }
        if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        if (put_user(sstatus.state, &src->s.status.state) ||
@@ -519,26 +510,24 @@ static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
                if (err < 0)
                        return err;
        }
-       snd_pcm_stream_lock_irq(substream);
-       if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
-               err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
-               if (err < 0) {
-                       snd_pcm_stream_unlock_irq(substream);
-                       return err;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
+                       err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
+                       if (err < 0)
+                               return err;
+               } else {
+                       sync_cp->appl_ptr = control->appl_ptr;
                }
-       } else {
-               sync_cp->appl_ptr = control->appl_ptr;
+               if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+                       control->avail_min = sync_cp->avail_min;
+               else
+                       sync_cp->avail_min = control->avail_min;
+               sync_ptr.s.status.state = status->state;
+               sync_ptr.s.status.hw_ptr = status->hw_ptr;
+               sync_ptr.s.status.tstamp = status->tstamp;
+               sync_ptr.s.status.suspended_state = status->suspended_state;
+               sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
        }
-       if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
-               control->avail_min = sync_cp->avail_min;
-       else
-               sync_cp->avail_min = control->avail_min;
-       sync_ptr.s.status.state = status->state;
-       sync_ptr.s.status.hw_ptr = status->hw_ptr;
-       sync_ptr.s.status.tstamp = status->tstamp;
-       sync_ptr.s.status.suspended_state = status->suspended_state;
-       sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
-       snd_pcm_stream_unlock_irq(substream);
        if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
index 41103e5c43ce5bf852908a3b72ed73468f21695a..6f73b3c2c205ee201552fb4fb1b2efbc6a63b1d0 100644 (file)
@@ -1744,8 +1744,8 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
                                   void *arg)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned long flags;
-       snd_pcm_stream_lock_irqsave(substream, flags);
+
+       guard(pcm_stream_lock_irqsave)(substream);
        if (snd_pcm_running(substream) &&
            snd_pcm_update_hw_ptr(substream) >= 0)
                runtime->status->hw_ptr %= runtime->buffer_size;
@@ -1753,7 +1753,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
                runtime->status->hw_ptr = 0;
                runtime->hw_ptr_wrap = 0;
        }
-       snd_pcm_stream_unlock_irqrestore(substream, flags);
        return 0;
 }
 
@@ -1899,14 +1898,11 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock);
  */
 void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
 {
-       unsigned long flags;
-
        if (snd_BUG_ON(!substream))
                return;
 
-       snd_pcm_stream_lock_irqsave(substream, flags);
+       guard(pcm_stream_lock_irqsave)(substream);
        snd_pcm_period_elapsed_under_stream_lock(substream);
-       snd_pcm_stream_unlock_irqrestore(substream, flags);
 }
 EXPORT_SYMBOL(snd_pcm_period_elapsed);
 
index a0b9514716995fb65c31ca0fef62a8368d359416..506386959f0848f789de5042ea9a4c15bc4dc7f9 100644 (file)
@@ -38,17 +38,15 @@ static void __update_allocated_size(struct snd_card *card, ssize_t bytes)
 
 static void update_allocated_size(struct snd_card *card, ssize_t bytes)
 {
-       mutex_lock(&card->memory_mutex);
+       guard(mutex)(&card->memory_mutex);
        __update_allocated_size(card, bytes);
-       mutex_unlock(&card->memory_mutex);
 }
 
 static void decrease_allocated_size(struct snd_card *card, size_t bytes)
 {
-       mutex_lock(&card->memory_mutex);
+       guard(mutex)(&card->memory_mutex);
        WARN_ON(card->total_pcm_alloc_bytes < bytes);
        __update_allocated_size(card, -(ssize_t)bytes);
-       mutex_unlock(&card->memory_mutex);
 }
 
 static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
@@ -58,14 +56,12 @@ static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
        int err;
 
        /* check and reserve the requested size */
-       mutex_lock(&card->memory_mutex);
-       if (max_alloc_per_card &&
-           card->total_pcm_alloc_bytes + size > max_alloc_per_card) {
-               mutex_unlock(&card->memory_mutex);
-               return -ENOMEM;
+       scoped_guard(mutex, &card->memory_mutex) {
+               if (max_alloc_per_card &&
+                   card->total_pcm_alloc_bytes + size > max_alloc_per_card)
+                       return -ENOMEM;
+               __update_allocated_size(card, size);
        }
-       __update_allocated_size(card, size);
-       mutex_unlock(&card->memory_mutex);
 
        if (str == SNDRV_PCM_STREAM_PLAYBACK)
                dir = DMA_TO_DEVICE;
@@ -191,20 +187,20 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
        size_t size;
        struct snd_dma_buffer new_dmab;
 
-       mutex_lock(&substream->pcm->open_mutex);
+       guard(mutex)(&substream->pcm->open_mutex);
        if (substream->runtime) {
                buffer->error = -EBUSY;
-               goto unlock;
+               return;
        }
        if (!snd_info_get_line(buffer, line, sizeof(line))) {
                snd_info_get_str(str, line, sizeof(str));
                size = simple_strtoul(str, NULL, 10) * 1024;
                if ((size != 0 && size < 8192) || size > substream->dma_max) {
                        buffer->error = -EINVAL;
-                       goto unlock;
+                       return;
                }
                if (substream->dma_buffer.bytes == size)
-                       goto unlock;
+                       return;
                memset(&new_dmab, 0, sizeof(new_dmab));
                new_dmab.dev = substream->dma_buffer.dev;
                if (size > 0) {
@@ -218,7 +214,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
                                         substream->pcm->card->number, substream->pcm->device,
                                         substream->stream ? 'c' : 'p', substream->number,
                                         substream->pcm->name, size);
-                               goto unlock;
+                               return;
                        }
                        substream->buffer_bytes_max = size;
                } else {
@@ -230,8 +226,6 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
        } else {
                buffer->error = -EINVAL;
        }
- unlock:
-       mutex_unlock(&substream->pcm->open_mutex);
 }
 
 static inline void preallocate_info_init(struct snd_pcm_substream *substream)
index 21baf6bf7e25a048e64d37331b0109f2ad7ec354..0b76e76823d288d92f6e3355eda2a08cf15ddf9c 100644 (file)
@@ -236,7 +236,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
 int snd_pcm_info_user(struct snd_pcm_substream *substream,
                      struct snd_pcm_info __user * _info)
 {
-       struct snd_pcm_info *info;
+       struct snd_pcm_info *info __free(kfree) = NULL;
        int err;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -247,7 +247,6 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
                if (copy_to_user(_info, info, sizeof(*info)))
                        err = -EFAULT;
        }
-       kfree(info);
        return err;
 }
 
@@ -359,7 +358,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_constraints *constrs =
                                        &substream->runtime->hw_constraints;
        unsigned int k;
-       unsigned int *rstamps;
+       unsigned int *rstamps __free(kfree) = NULL;
        unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
        unsigned int stamp;
        struct snd_pcm_hw_rule *r;
@@ -435,10 +434,8 @@ retry:
                }
 
                changed = r->func(params, r);
-               if (changed < 0) {
-                       err = changed;
-                       goto out;
-               }
+               if (changed < 0)
+                       return changed;
 
                /*
                 * When the parameter is changed, notify it to the caller
@@ -469,8 +466,6 @@ retry:
        if (again)
                goto retry;
 
- out:
-       kfree(rstamps);
        return err;
 }
 
@@ -576,26 +571,24 @@ EXPORT_SYMBOL(snd_pcm_hw_refine);
 static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params __user * _params)
 {
-       struct snd_pcm_hw_params *params;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
        int err;
 
        params = memdup_user(_params, sizeof(*params));
        if (IS_ERR(params))
-               return PTR_ERR(params);
+               return PTR_ERR(no_free_ptr(params));
 
        err = snd_pcm_hw_refine(substream, params);
        if (err < 0)
-               goto end;
+               return err;
 
        err = fixup_unreferenced_params(substream, params);
        if (err < 0)
-               goto end;
+               return err;
 
        if (copy_to_user(_params, params, sizeof(*params)))
-               err = -EFAULT;
-end:
-       kfree(params);
-       return err;
+               return -EFAULT;
+       return 0;
 }
 
 static int period_to_usecs(struct snd_pcm_runtime *runtime)
@@ -616,10 +609,9 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
 static void snd_pcm_set_state(struct snd_pcm_substream *substream,
                              snd_pcm_state_t state)
 {
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
                __snd_pcm_set_state(substream->runtime, state);
-       snd_pcm_stream_unlock_irq(substream);
 }
 
 static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
@@ -745,20 +737,20 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        err = snd_pcm_buffer_access_lock(runtime);
        if (err < 0)
                return err;
-       snd_pcm_stream_lock_irq(substream);
-       switch (runtime->state) {
-       case SNDRV_PCM_STATE_OPEN:
-       case SNDRV_PCM_STATE_SETUP:
-       case SNDRV_PCM_STATE_PREPARED:
-               if (!is_oss_stream(substream) &&
-                   atomic_read(&substream->mmap_count))
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               switch (runtime->state) {
+               case SNDRV_PCM_STATE_OPEN:
+               case SNDRV_PCM_STATE_SETUP:
+               case SNDRV_PCM_STATE_PREPARED:
+                       if (!is_oss_stream(substream) &&
+                           atomic_read(&substream->mmap_count))
+                               err = -EBADFD;
+                       break;
+               default:
                        err = -EBADFD;
-               break;
-       default:
-               err = -EBADFD;
-               break;
+                       break;
+               }
        }
-       snd_pcm_stream_unlock_irq(substream);
        if (err)
                goto unlock;
 
@@ -869,21 +861,19 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params __user * _params)
 {
-       struct snd_pcm_hw_params *params;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
        int err;
 
        params = memdup_user(_params, sizeof(*params));
        if (IS_ERR(params))
-               return PTR_ERR(params);
+               return PTR_ERR(no_free_ptr(params));
 
        err = snd_pcm_hw_params(substream, params);
        if (err < 0)
-               goto end;
+               return err;
 
        if (copy_to_user(_params, params, sizeof(*params)))
-               err = -EFAULT;
-end:
-       kfree(params);
+               return -EFAULT;
        return err;
 }
 
@@ -910,18 +900,18 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
        result = snd_pcm_buffer_access_lock(runtime);
        if (result < 0)
                return result;
-       snd_pcm_stream_lock_irq(substream);
-       switch (runtime->state) {
-       case SNDRV_PCM_STATE_SETUP:
-       case SNDRV_PCM_STATE_PREPARED:
-               if (atomic_read(&substream->mmap_count))
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               switch (runtime->state) {
+               case SNDRV_PCM_STATE_SETUP:
+               case SNDRV_PCM_STATE_PREPARED:
+                       if (atomic_read(&substream->mmap_count))
+                               result = -EBADFD;
+                       break;
+               default:
                        result = -EBADFD;
-               break;
-       default:
-               result = -EBADFD;
-               break;
+                       break;
+               }
        }
-       snd_pcm_stream_unlock_irq(substream);
        if (result)
                goto unlock;
        result = do_hw_free(substream);
@@ -941,12 +931,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
        if (PCM_RUNTIME_CHECK(substream))
                return -ENXIO;
        runtime = substream->runtime;
-       snd_pcm_stream_lock_irq(substream);
-       if (runtime->state == SNDRV_PCM_STATE_OPEN) {
-               snd_pcm_stream_unlock_irq(substream);
-               return -EBADFD;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (runtime->state == SNDRV_PCM_STATE_OPEN)
+                       return -EBADFD;
        }
-       snd_pcm_stream_unlock_irq(substream);
 
        if (params->tstamp_mode < 0 ||
            params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
@@ -966,24 +954,24 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
                        return -EINVAL;
        }
        err = 0;
-       snd_pcm_stream_lock_irq(substream);
-       runtime->tstamp_mode = params->tstamp_mode;
-       if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
-               runtime->tstamp_type = params->tstamp_type;
-       runtime->period_step = params->period_step;
-       runtime->control->avail_min = params->avail_min;
-       runtime->start_threshold = params->start_threshold;
-       runtime->stop_threshold = params->stop_threshold;
-       runtime->silence_threshold = params->silence_threshold;
-       runtime->silence_size = params->silence_size;
-        params->boundary = runtime->boundary;
-       if (snd_pcm_running(substream)) {
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-                   runtime->silence_size > 0)
-                       snd_pcm_playback_silence(substream, ULONG_MAX);
-               err = snd_pcm_update_state(substream, runtime);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               runtime->tstamp_mode = params->tstamp_mode;
+               if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
+                       runtime->tstamp_type = params->tstamp_type;
+               runtime->period_step = params->period_step;
+               runtime->control->avail_min = params->avail_min;
+               runtime->start_threshold = params->start_threshold;
+               runtime->stop_threshold = params->stop_threshold;
+               runtime->silence_threshold = params->silence_threshold;
+               runtime->silence_size = params->silence_size;
+               params->boundary = runtime->boundary;
+               if (snd_pcm_running(substream)) {
+                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+                           runtime->silence_size > 0)
+                               snd_pcm_playback_silence(substream, ULONG_MAX);
+                       err = snd_pcm_update_state(substream, runtime);
+               }
        }
-       snd_pcm_stream_unlock_irq(substream);
        return err;
 }
 
@@ -1017,7 +1005,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
 
        snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
                                        &runtime->audio_tstamp_config);
@@ -1038,7 +1026,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
        status->state = runtime->state;
        status->suspended_state = runtime->suspended_state;
        if (status->state == SNDRV_PCM_STATE_OPEN)
-               goto _end;
+               return 0;
        status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
        status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
        if (snd_pcm_running(substream)) {
@@ -1083,8 +1071,6 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
        status->overrange = runtime->overrange;
        runtime->avail_max = 0;
        runtime->overrange = 0;
- _end:
-       snd_pcm_stream_unlock_irq(substream);
        return 0;
 }
 
@@ -1169,12 +1155,10 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
        
        channel = info->channel;
        runtime = substream->runtime;
-       snd_pcm_stream_lock_irq(substream);
-       if (runtime->state == SNDRV_PCM_STATE_OPEN) {
-               snd_pcm_stream_unlock_irq(substream);
-               return -EBADFD;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (runtime->state == SNDRV_PCM_STATE_OPEN)
+                       return -EBADFD;
        }
-       snd_pcm_stream_unlock_irq(substream);
        if (channel >= runtime->channels)
                return -EINVAL;
        memset(info, 0, sizeof(*info));
@@ -1395,12 +1379,8 @@ static int snd_pcm_action_lock_irq(const struct action_ops *ops,
                                   struct snd_pcm_substream *substream,
                                   snd_pcm_state_t state)
 {
-       int res;
-
-       snd_pcm_stream_lock_irq(substream);
-       res = snd_pcm_action(ops, substream, state);
-       snd_pcm_stream_unlock_irq(substream);
-       return res;
+       guard(pcm_stream_lock_irq)(substream);
+       return snd_pcm_action(ops, substream, state);
 }
 
 /*
@@ -1412,17 +1392,15 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
        int res;
 
        /* Guarantee the group members won't change during non-atomic action */
-       down_read(&snd_pcm_link_rwsem);
+       guard(rwsem_read)(&snd_pcm_link_rwsem);
        res = snd_pcm_buffer_access_lock(substream->runtime);
        if (res < 0)
-               goto unlock;
+               return res;
        if (snd_pcm_stream_linked(substream))
                res = snd_pcm_action_group(ops, substream, state, false);
        else
                res = snd_pcm_action_single(ops, substream, state);
        snd_pcm_buffer_access_unlock(substream->runtime);
- unlock:
-       up_read(&snd_pcm_link_rwsem);
        return res;
 }
 
@@ -1592,12 +1570,9 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream)
  */
 int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
 {
-       unsigned long flags;
-
-       snd_pcm_stream_lock_irqsave(substream, flags);
+       guard(pcm_stream_lock_irqsave)(substream);
        if (substream->runtime && snd_pcm_running(substream))
                __snd_pcm_xrun(substream);
-       snd_pcm_stream_unlock_irqrestore(substream, flags);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
@@ -1749,14 +1724,9 @@ static const struct action_ops snd_pcm_action_suspend = {
  */
 static int snd_pcm_suspend(struct snd_pcm_substream *substream)
 {
-       int err;
-       unsigned long flags;
-
-       snd_pcm_stream_lock_irqsave(substream, flags);
-       err = snd_pcm_action(&snd_pcm_action_suspend, substream,
-                            ACTION_ARG_IGNORE);
-       snd_pcm_stream_unlock_irqrestore(substream, flags);
-       return err;
+       guard(pcm_stream_lock_irqsave)(substream);
+       return snd_pcm_action(&snd_pcm_action_suspend, substream,
+                             ACTION_ARG_IGNORE);
 }
 
 /**
@@ -1872,22 +1842,17 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
 static int snd_pcm_xrun(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       int result;
 
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        switch (runtime->state) {
        case SNDRV_PCM_STATE_XRUN:
-               result = 0;     /* already there */
-               break;
+               return 0;       /* already there */
        case SNDRV_PCM_STATE_RUNNING:
                __snd_pcm_xrun(substream);
-               result = 0;
-               break;
+               return 0;
        default:
-               result = -EBADFD;
+               return -EBADFD;
        }
-       snd_pcm_stream_unlock_irq(substream);
-       return result;
 }
 
 /*
@@ -1916,13 +1881,12 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream,
        int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
        if (err < 0)
                return err;
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        runtime->hw_ptr_base = 0;
        runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
                runtime->status->hw_ptr % runtime->period_size;
        runtime->silence_start = runtime->status->hw_ptr;
        runtime->silence_filled = 0;
-       snd_pcm_stream_unlock_irq(substream);
        return 0;
 }
 
@@ -1930,12 +1894,11 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream,
                               snd_pcm_state_t state)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        runtime->control->appl_ptr = runtime->status->hw_ptr;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, ULONG_MAX);
-       snd_pcm_stream_unlock_irq(substream);
 }
 
 static const struct action_ops snd_pcm_action_reset = {
@@ -2011,16 +1974,16 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
        else
                f_flags = substream->f_flags;
 
-       snd_pcm_stream_lock_irq(substream);
-       switch (substream->runtime->state) {
-       case SNDRV_PCM_STATE_PAUSED:
-               snd_pcm_pause(substream, false);
-               fallthrough;
-       case SNDRV_PCM_STATE_SUSPENDED:
-               snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
-               break;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               switch (substream->runtime->state) {
+               case SNDRV_PCM_STATE_PAUSED:
+                       snd_pcm_pause(substream, false);
+                       fallthrough;
+               case SNDRV_PCM_STATE_SUSPENDED:
+                       snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+                       break;
+               }
        }
-       snd_pcm_stream_unlock_irq(substream);
 
        return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
                                        substream,
@@ -2237,14 +2200,13 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
            runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
                return -EBADFD;
 
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        /* resume pause */
        if (runtime->state == SNDRV_PCM_STATE_PAUSED)
                snd_pcm_pause(substream, false);
 
        snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
        /* runtime->control->appl_ptr = runtime->status->hw_ptr; */
-       snd_pcm_stream_unlock_irq(substream);
 
        return result;
 }
@@ -2273,53 +2235,44 @@ static bool is_pcm_file(struct file *file)
  */
 static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
 {
-       int res = 0;
        struct snd_pcm_file *pcm_file;
        struct snd_pcm_substream *substream1;
-       struct snd_pcm_group *group, *target_group;
+       struct snd_pcm_group *group __free(kfree) = NULL;
+       struct snd_pcm_group *target_group;
        bool nonatomic = substream->pcm->nonatomic;
-       struct fd f = fdget(fd);
+       CLASS(fd, f)(fd);
 
        if (!f.file)
                return -EBADFD;
-       if (!is_pcm_file(f.file)) {
-               res = -EBADFD;
-               goto _badf;
-       }
+       if (!is_pcm_file(f.file))
+               return -EBADFD;
+
        pcm_file = f.file->private_data;
        substream1 = pcm_file->substream;
 
-       if (substream == substream1) {
-               res = -EINVAL;
-               goto _badf;
-       }
+       if (substream == substream1)
+               return -EINVAL;
 
        group = kzalloc(sizeof(*group), GFP_KERNEL);
-       if (!group) {
-               res = -ENOMEM;
-               goto _nolock;
-       }
+       if (!group)
+               return -ENOMEM;
        snd_pcm_group_init(group);
 
-       down_write(&snd_pcm_link_rwsem);
+       guard(rwsem_write)(&snd_pcm_link_rwsem);
        if (substream->runtime->state == SNDRV_PCM_STATE_OPEN ||
            substream->runtime->state != substream1->runtime->state ||
-           substream->pcm->nonatomic != substream1->pcm->nonatomic) {
-               res = -EBADFD;
-               goto _end;
-       }
-       if (snd_pcm_stream_linked(substream1)) {
-               res = -EALREADY;
-               goto _end;
-       }
+           substream->pcm->nonatomic != substream1->pcm->nonatomic)
+               return -EBADFD;
+       if (snd_pcm_stream_linked(substream1))
+               return -EALREADY;
 
-       snd_pcm_stream_lock_irq(substream);
-       if (!snd_pcm_stream_linked(substream)) {
-               snd_pcm_group_assign(substream, group);
-               group = NULL; /* assigned, don't free this one below */
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (!snd_pcm_stream_linked(substream)) {
+                       snd_pcm_group_assign(substream, group);
+                       group = NULL; /* assigned, don't free this one below */
+               }
+               target_group = substream->group;
        }
-       target_group = substream->group;
-       snd_pcm_stream_unlock_irq(substream);
 
        snd_pcm_group_lock_irq(target_group, nonatomic);
        snd_pcm_stream_lock_nested(substream1);
@@ -2327,13 +2280,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
        refcount_inc(&target_group->refs);
        snd_pcm_stream_unlock(substream1);
        snd_pcm_group_unlock_irq(target_group, nonatomic);
- _end:
-       up_write(&snd_pcm_link_rwsem);
- _nolock:
-       kfree(group);
- _badf:
-       fdput(f);
-       return res;
+       return 0;
 }
 
 static void relink_to_local(struct snd_pcm_substream *substream)
@@ -2348,14 +2295,11 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
        struct snd_pcm_group *group;
        bool nonatomic = substream->pcm->nonatomic;
        bool do_free = false;
-       int res = 0;
 
-       down_write(&snd_pcm_link_rwsem);
+       guard(rwsem_write)(&snd_pcm_link_rwsem);
 
-       if (!snd_pcm_stream_linked(substream)) {
-               res = -EALREADY;
-               goto _end;
-       }
+       if (!snd_pcm_stream_linked(substream))
+               return -EALREADY;
 
        group = substream->group;
        snd_pcm_group_lock_irq(group, nonatomic);
@@ -2374,10 +2318,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
        snd_pcm_group_unlock_irq(group, nonatomic);
        if (do_free)
                kfree(group);
-
-       _end:
-       up_write(&snd_pcm_link_rwsem);
-       return res;
+       return 0;
 }
 
 /*
@@ -2950,10 +2891,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
        /* block until the device gets woken up as it may touch the hardware */
        snd_power_wait(pcm->card);
 
-       mutex_lock(&pcm->open_mutex);
-       snd_pcm_release_substream(substream);
-       kfree(pcm_file);
-       mutex_unlock(&pcm->open_mutex);
+       scoped_guard(mutex, &pcm->open_mutex) {
+               snd_pcm_release_substream(substream);
+               kfree(pcm_file);
+       }
        wake_up(&pcm->open_wait);
        module_put(pcm->card->module);
        snd_card_file_remove(pcm->card, file);
@@ -3037,12 +2978,12 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
        if (frames == 0)
                return 0;
 
-       snd_pcm_stream_lock_irq(substream);
-       ret = do_pcm_hwsync(substream);
-       if (!ret)
-               ret = rewind_appl_ptr(substream, frames,
-                                     snd_pcm_hw_avail(substream));
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               ret = do_pcm_hwsync(substream);
+               if (!ret)
+                       ret = rewind_appl_ptr(substream, frames,
+                                             snd_pcm_hw_avail(substream));
+       }
        if (ret >= 0)
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        return ret;
@@ -3056,12 +2997,12 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
        if (frames == 0)
                return 0;
 
-       snd_pcm_stream_lock_irq(substream);
-       ret = do_pcm_hwsync(substream);
-       if (!ret)
-               ret = forward_appl_ptr(substream, frames,
-                                      snd_pcm_avail(substream));
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               ret = do_pcm_hwsync(substream);
+               if (!ret)
+                       ret = forward_appl_ptr(substream, frames,
+                                              snd_pcm_avail(substream));
+       }
        if (ret >= 0)
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        return ret;
@@ -3072,11 +3013,11 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
 {
        int err;
 
-       snd_pcm_stream_lock_irq(substream);
-       err = do_pcm_hwsync(substream);
-       if (delay && !err)
-               *delay = snd_pcm_calc_delay(substream);
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               err = do_pcm_hwsync(substream);
+               if (delay && !err)
+                       *delay = snd_pcm_calc_delay(substream);
+       }
        snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
 
        return err;
@@ -3108,27 +3049,25 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
                if (err < 0)
                        return err;
        }
-       snd_pcm_stream_lock_irq(substream);
-       if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
-               err = pcm_lib_apply_appl_ptr(substream,
-                                            sync_ptr.c.control.appl_ptr);
-               if (err < 0) {
-                       snd_pcm_stream_unlock_irq(substream);
-                       return err;
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
+                       err = pcm_lib_apply_appl_ptr(substream,
+                                                    sync_ptr.c.control.appl_ptr);
+                       if (err < 0)
+                               return err;
+               } else {
+                       sync_ptr.c.control.appl_ptr = control->appl_ptr;
                }
-       } else {
-               sync_ptr.c.control.appl_ptr = control->appl_ptr;
+               if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+                       control->avail_min = sync_ptr.c.control.avail_min;
+               else
+                       sync_ptr.c.control.avail_min = control->avail_min;
+               sync_ptr.s.status.state = status->state;
+               sync_ptr.s.status.hw_ptr = status->hw_ptr;
+               sync_ptr.s.status.tstamp = status->tstamp;
+               sync_ptr.s.status.suspended_state = status->suspended_state;
+               sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
        }
-       if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
-               control->avail_min = sync_ptr.c.control.avail_min;
-       else
-               sync_ptr.c.control.avail_min = control->avail_min;
-       sync_ptr.s.status.state = status->state;
-       sync_ptr.s.status.hw_ptr = status->hw_ptr;
-       sync_ptr.s.status.tstamp = status->tstamp;
-       sync_ptr.s.status.suspended_state = status->suspended_state;
-       sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
-       snd_pcm_stream_unlock_irq(substream);
        if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
@@ -3206,27 +3145,25 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
        boundary = recalculate_boundary(runtime);
        if (! boundary)
                boundary = 0x7fffffff;
-       snd_pcm_stream_lock_irq(substream);
-       /* FIXME: we should consider the boundary for the sync from app */
-       if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
-               err = pcm_lib_apply_appl_ptr(substream,
-                               scontrol.appl_ptr);
-               if (err < 0) {
-                       snd_pcm_stream_unlock_irq(substream);
-                       return err;
-               }
-       } else
-               scontrol.appl_ptr = control->appl_ptr % boundary;
-       if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
-               control->avail_min = scontrol.avail_min;
-       else
-               scontrol.avail_min = control->avail_min;
-       sstatus.state = status->state;
-       sstatus.hw_ptr = status->hw_ptr % boundary;
-       sstatus.tstamp = status->tstamp;
-       sstatus.suspended_state = status->suspended_state;
-       sstatus.audio_tstamp = status->audio_tstamp;
-       snd_pcm_stream_unlock_irq(substream);
+       scoped_guard(pcm_stream_lock_irq, substream) {
+               /* FIXME: we should consider the boundary for the sync from app */
+               if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
+                       err = pcm_lib_apply_appl_ptr(substream,
+                                                    scontrol.appl_ptr);
+                       if (err < 0)
+                               return err;
+               } else
+                       scontrol.appl_ptr = control->appl_ptr % boundary;
+               if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+                       control->avail_min = scontrol.avail_min;
+               else
+                       scontrol.avail_min = control->avail_min;
+               sstatus.state = status->state;
+               sstatus.hw_ptr = status->hw_ptr % boundary;
+               sstatus.tstamp = status->tstamp;
+               sstatus.suspended_state = status->suspended_state;
+               sstatus.audio_tstamp = status->audio_tstamp;
+       }
        if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
        if (put_user(sstatus.state, &src->s.status.state) ||
@@ -3284,7 +3221,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
 {
        struct snd_xfern xfern;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       void *bufs;
+       void *bufs __free(kfree) = NULL;
        snd_pcm_sframes_t result;
 
        if (runtime->state == SNDRV_PCM_STATE_OPEN)
@@ -3298,12 +3235,11 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
 
        bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
        if (IS_ERR(bufs))
-               return PTR_ERR(bufs);
+               return PTR_ERR(no_free_ptr(bufs));
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
        else
                result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
-       kfree(bufs);
        if (put_user(result, &_xfern->result))
                return -EFAULT;
        return result < 0 ? result : 0;
@@ -3571,7 +3507,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
        struct snd_pcm_runtime *runtime;
        snd_pcm_sframes_t result;
        unsigned long i;
-       void __user **bufs;
+       void __user **bufs __free(kfree) = NULL;
        snd_pcm_uframes_t frames;
        const struct iovec *iov = iter_iov(to);
 
@@ -3600,7 +3536,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
        result = snd_pcm_lib_readv(substream, bufs, frames);
        if (result > 0)
                result = frames_to_bytes(runtime, result);
-       kfree(bufs);
        return result;
 }
 
@@ -3611,7 +3546,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
        struct snd_pcm_runtime *runtime;
        snd_pcm_sframes_t result;
        unsigned long i;
-       void __user **bufs;
+       void __user **bufs __free(kfree) = NULL;
        snd_pcm_uframes_t frames;
        const struct iovec *iov = iter_iov(from);
 
@@ -3639,7 +3574,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
        result = snd_pcm_lib_writev(substream, bufs, frames);
        if (result > 0)
                result = frames_to_bytes(runtime, result);
-       kfree(bufs);
        return result;
 }
 
@@ -3668,7 +3602,7 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
        poll_wait(file, &runtime->sleep, wait);
 
        mask = 0;
-       snd_pcm_stream_lock_irq(substream);
+       guard(pcm_stream_lock_irq)(substream);
        avail = snd_pcm_avail(substream);
        switch (runtime->state) {
        case SNDRV_PCM_STATE_RUNNING:
@@ -3688,7 +3622,6 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
                mask = ok | EPOLLERR;
                break;
        }
-       snd_pcm_stream_unlock_irq(substream);
        return mask;
 }
 
@@ -4081,8 +4014,8 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara
 static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params_old __user * _oparams)
 {
-       struct snd_pcm_hw_params *params;
-       struct snd_pcm_hw_params_old *oparams = NULL;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
+       struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
        int err;
 
        params = kmalloc(sizeof(*params), GFP_KERNEL);
@@ -4090,34 +4023,28 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
                return -ENOMEM;
 
        oparams = memdup_user(_oparams, sizeof(*oparams));
-       if (IS_ERR(oparams)) {
-               err = PTR_ERR(oparams);
-               goto out;
-       }
+       if (IS_ERR(oparams))
+               return PTR_ERR(no_free_ptr(oparams));
        snd_pcm_hw_convert_from_old_params(params, oparams);
        err = snd_pcm_hw_refine(substream, params);
        if (err < 0)
-               goto out_old;
+               return err;
 
        err = fixup_unreferenced_params(substream, params);
        if (err < 0)
-               goto out_old;
+               return err;
 
        snd_pcm_hw_convert_to_old_params(oparams, params);
        if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
-               err = -EFAULT;
-out_old:
-       kfree(oparams);
-out:
-       kfree(params);
-       return err;
+               return -EFAULT;
+       return 0;
 }
 
 static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params_old __user * _oparams)
 {
-       struct snd_pcm_hw_params *params;
-       struct snd_pcm_hw_params_old *oparams = NULL;
+       struct snd_pcm_hw_params *params __free(kfree) = NULL;
+       struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
        int err;
 
        params = kmalloc(sizeof(*params), GFP_KERNEL);
@@ -4125,24 +4052,18 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
                return -ENOMEM;
 
        oparams = memdup_user(_oparams, sizeof(*oparams));
-       if (IS_ERR(oparams)) {
-               err = PTR_ERR(oparams);
-               goto out;
-       }
+       if (IS_ERR(oparams))
+               return PTR_ERR(no_free_ptr(oparams));
 
        snd_pcm_hw_convert_from_old_params(params, oparams);
        err = snd_pcm_hw_params(substream, params);
        if (err < 0)
-               goto out_old;
+               return err;
 
        snd_pcm_hw_convert_to_old_params(oparams, params);
        if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
-               err = -EFAULT;
-out_old:
-       kfree(oparams);
-out:
-       kfree(params);
-       return err;
+               return -EFAULT;
+       return 0;
 }
 #endif /* CONFIG_SND_SUPPORT_OLD_API */
 
index 1431cb997808d071d44efadba2b8a1d49117ee25..7accf9a1ddf4c625255fd47794d6ff1d5cbf068c 100644 (file)
@@ -105,13 +105,8 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime)
 
 static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
 {
-       unsigned long flags;
-       bool ready;
-
-       spin_lock_irqsave(&substream->lock, flags);
-       ready = __snd_rawmidi_ready(substream->runtime);
-       spin_unlock_irqrestore(&substream->lock, flags);
-       return ready;
+       guard(spinlock_irqsave)(&substream->lock);
+       return __snd_rawmidi_ready(substream->runtime);
 }
 
 static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream,
@@ -238,12 +233,9 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
 static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream,
                               bool is_input)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&substream->lock, flags);
+       guard(spinlock_irqsave)(&substream->lock);
        if (substream->opened && substream->runtime)
                __reset_runtime_ptrs(substream->runtime, is_input);
-       spin_unlock_irqrestore(&substream->lock, flags);
 }
 
 int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
@@ -260,33 +252,29 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
        long timeout;
        struct snd_rawmidi_runtime *runtime;
 
-       spin_lock_irq(&substream->lock);
-       runtime = substream->runtime;
-       if (!substream->opened || !runtime || !runtime->buffer) {
-               err = -EINVAL;
-       } else {
+       scoped_guard(spinlock_irq, &substream->lock) {
+               runtime = substream->runtime;
+               if (!substream->opened || !runtime || !runtime->buffer)
+                       return -EINVAL;
                snd_rawmidi_buffer_ref(runtime);
                runtime->drain = 1;
        }
-       spin_unlock_irq(&substream->lock);
-       if (err < 0)
-               return err;
 
        timeout = wait_event_interruptible_timeout(runtime->sleep,
                                (runtime->avail >= runtime->buffer_size),
                                10*HZ);
 
-       spin_lock_irq(&substream->lock);
-       if (signal_pending(current))
-               err = -ERESTARTSYS;
-       if (runtime->avail < runtime->buffer_size && !timeout) {
-               rmidi_warn(substream->rmidi,
-                          "rawmidi drain error (avail = %li, buffer_size = %li)\n",
-                          (long)runtime->avail, (long)runtime->buffer_size);
-               err = -EIO;
+       scoped_guard(spinlock_irq, &substream->lock) {
+               if (signal_pending(current))
+                       err = -ERESTARTSYS;
+               if (runtime->avail < runtime->buffer_size && !timeout) {
+                       rmidi_warn(substream->rmidi,
+                                  "rawmidi drain error (avail = %li, buffer_size = %li)\n",
+                                  (long)runtime->avail, (long)runtime->buffer_size);
+                       err = -EIO;
+               }
+               runtime->drain = 0;
        }
-       runtime->drain = 0;
-       spin_unlock_irq(&substream->lock);
 
        if (err != -ERESTARTSYS) {
                /* we need wait a while to make sure that Tx FIFOs are empty */
@@ -297,9 +285,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
                snd_rawmidi_drop_output(substream);
        }
 
-       spin_lock_irq(&substream->lock);
-       snd_rawmidi_buffer_unref(runtime);
-       spin_unlock_irq(&substream->lock);
+       scoped_guard(spinlock_irq, &substream->lock)
+               snd_rawmidi_buffer_unref(runtime);
 
        return err;
 }
@@ -363,14 +350,13 @@ static int open_substream(struct snd_rawmidi *rmidi,
                        snd_rawmidi_runtime_free(substream);
                        return err;
                }
-               spin_lock_irq(&substream->lock);
+               guard(spinlock_irq)(&substream->lock);
                substream->opened = 1;
                substream->active_sensing = 0;
                if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
                        substream->append = 1;
                substream->pid = get_pid(task_pid(current));
                rmidi->streams[substream->stream].substream_opened++;
-               spin_unlock_irq(&substream->lock);
        }
        substream->use_count++;
        return 0;
@@ -433,9 +419,8 @@ int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
        if (!try_module_get(rmidi->card->module))
                return -ENXIO;
 
-       mutex_lock(&rmidi->open_mutex);
+       guard(mutex)(&rmidi->open_mutex);
        err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
-       mutex_unlock(&rmidi->open_mutex);
        if (err < 0)
                module_put(rmidi->card->module);
        return err;
@@ -568,10 +553,10 @@ static void close_substream(struct snd_rawmidi *rmidi,
                }
                snd_rawmidi_buffer_ref_sync(substream);
        }
-       spin_lock_irq(&substream->lock);
-       substream->opened = 0;
-       substream->append = 0;
-       spin_unlock_irq(&substream->lock);
+       scoped_guard(spinlock_irq, &substream->lock) {
+               substream->opened = 0;
+               substream->append = 0;
+       }
        substream->ops->close(substream);
        if (substream->runtime->private_free)
                substream->runtime->private_free(substream);
@@ -586,7 +571,7 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
        struct snd_rawmidi *rmidi;
 
        rmidi = rfile->rmidi;
-       mutex_lock(&rmidi->open_mutex);
+       guard(mutex)(&rmidi->open_mutex);
        if (rfile->input) {
                close_substream(rmidi, rfile->input, 1);
                rfile->input = NULL;
@@ -596,7 +581,6 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
                rfile->output = NULL;
        }
        rfile->rmidi = NULL;
-       mutex_unlock(&rmidi->open_mutex);
        wake_up(&rmidi->open_wait);
 }
 
@@ -695,12 +679,8 @@ static int __snd_rawmidi_info_select(struct snd_card *card,
 
 int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
 {
-       int ret;
-
-       mutex_lock(&register_mutex);
-       ret = __snd_rawmidi_info_select(card, info);
-       mutex_unlock(&register_mutex);
-       return ret;
+       guard(mutex)(&register_mutex);
+       return __snd_rawmidi_info_select(card, info);
 }
 EXPORT_SYMBOL(snd_rawmidi_info_select);
 
@@ -744,9 +724,8 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
                newbuf = kvzalloc(params->buffer_size, GFP_KERNEL);
                if (!newbuf)
                        return -ENOMEM;
-               spin_lock_irq(&substream->lock);
+               guard(spinlock_irq)(&substream->lock);
                if (runtime->buffer_ref) {
-                       spin_unlock_irq(&substream->lock);
                        kvfree(newbuf);
                        return -EBUSY;
                }
@@ -754,7 +733,6 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
                runtime->buffer = newbuf;
                runtime->buffer_size = params->buffer_size;
                __reset_runtime_ptrs(runtime, is_input);
-               spin_unlock_irq(&substream->lock);
                kvfree(oldbuf);
        }
        runtime->avail_min = params->avail_min;
@@ -767,15 +745,12 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
        int err;
 
        snd_rawmidi_drain_output(substream);
-       mutex_lock(&substream->rmidi->open_mutex);
+       guard(mutex)(&substream->rmidi->open_mutex);
        if (substream->append && substream->use_count > 1)
-               err = -EBUSY;
-       else
-               err = resize_runtime_buffer(substream, params, false);
-
+               return -EBUSY;
+       err = resize_runtime_buffer(substream, params, false);
        if (!err)
                substream->active_sensing = !params->no_active_sensing;
-       mutex_unlock(&substream->rmidi->open_mutex);
        return err;
 }
 EXPORT_SYMBOL(snd_rawmidi_output_params);
@@ -788,7 +763,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
        int err;
 
        snd_rawmidi_drain_input(substream);
-       mutex_lock(&substream->rmidi->open_mutex);
+       guard(mutex)(&substream->rmidi->open_mutex);
        if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
                err = -EINVAL;
        else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
@@ -802,7 +777,6 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
                substream->framing = framing;
                substream->clock_type = clock_type;
        }
-       mutex_unlock(&substream->rmidi->open_mutex);
        return 0;
 }
 EXPORT_SYMBOL(snd_rawmidi_input_params);
@@ -814,9 +788,8 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
 
        memset(status, 0, sizeof(*status));
        status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
-       spin_lock_irq(&substream->lock);
+       guard(spinlock_irq)(&substream->lock);
        status->avail = runtime->avail;
-       spin_unlock_irq(&substream->lock);
        return 0;
 }
 
@@ -827,11 +800,10 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
 
        memset(status, 0, sizeof(*status));
        status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
-       spin_lock_irq(&substream->lock);
+       guard(spinlock_irq)(&substream->lock);
        status->avail = runtime->avail;
        status->xruns = runtime->xruns;
        runtime->xruns = 0;
-       spin_unlock_irq(&substream->lock);
        return 0;
 }
 
@@ -1025,19 +997,19 @@ static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp,
                return -EFAULT;
        if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
                device = SNDRV_RAWMIDI_DEVICES - 1;
-       mutex_lock(&register_mutex);
-       device = device < 0 ? 0 : device + 1;
-       for (; device < SNDRV_RAWMIDI_DEVICES; device++) {
-               rmidi = snd_rawmidi_search(card, device);
-               if (!rmidi)
-                       continue;
-               is_ump = rawmidi_is_ump(rmidi);
-               if (find_ump == is_ump)
-                       break;
+       scoped_guard(mutex, &register_mutex) {
+               device = device < 0 ? 0 : device + 1;
+               for (; device < SNDRV_RAWMIDI_DEVICES; device++) {
+                       rmidi = snd_rawmidi_search(card, device);
+                       if (!rmidi)
+                               continue;
+                       is_ump = rawmidi_is_ump(rmidi);
+                       if (find_ump == is_ump)
+                               break;
+               }
+               if (device == SNDRV_RAWMIDI_DEVICES)
+                       device = -1;
        }
-       if (device == SNDRV_RAWMIDI_DEVICES)
-               device = -1;
-       mutex_unlock(&register_mutex);
        if (put_user(device, argp))
                return -EFAULT;
        return 0;
@@ -1050,18 +1022,16 @@ static int snd_rawmidi_call_ump_ioctl(struct snd_card *card, int cmd,
 {
        struct snd_ump_endpoint_info __user *info = argp;
        struct snd_rawmidi *rmidi;
-       int device, ret;
+       int device;
 
        if (get_user(device, &info->device))
                return -EFAULT;
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        rmidi = snd_rawmidi_search(card, device);
        if (rmidi && rmidi->ops && rmidi->ops->ioctl)
-               ret = rmidi->ops->ioctl(rmidi, cmd, argp);
+               return rmidi->ops->ioctl(rmidi, cmd, argp);
        else
-               ret = -ENXIO;
-       mutex_unlock(&register_mutex);
-       return ret;
+               return -ENXIO;
 }
 #endif
 
@@ -1168,27 +1138,23 @@ static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substr
 int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
                        const unsigned char *buffer, int count)
 {
-       unsigned long flags;
        struct timespec64 ts64 = get_framing_tstamp(substream);
        int result = 0, count1;
        struct snd_rawmidi_runtime *runtime;
 
-       spin_lock_irqsave(&substream->lock, flags);
-       if (!substream->opened) {
-               result = -EBADFD;
-               goto unlock;
-       }
+       guard(spinlock_irqsave)(&substream->lock);
+       if (!substream->opened)
+               return -EBADFD;
        runtime = substream->runtime;
        if (!runtime || !runtime->buffer) {
                rmidi_dbg(substream->rmidi,
                          "snd_rawmidi_receive: input is not active!!!\n");
-               result = -EINVAL;
-               goto unlock;
+               return -EINVAL;
        }
 
        count = get_aligned_size(runtime, count);
        if (!count)
-               goto unlock;
+               return result;
 
        if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
                result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
@@ -1211,7 +1177,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
                        count1 = runtime->buffer_size - runtime->avail;
                count1 = get_aligned_size(runtime, count1);
                if (!count1)
-                       goto unlock;
+                       return result;
                memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1);
                runtime->hw_ptr += count1;
                runtime->hw_ptr %= runtime->buffer_size;
@@ -1239,8 +1205,6 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
                else if (__snd_rawmidi_ready(runtime))
                        wake_up(&runtime->sleep);
        }
- unlock:
-       spin_unlock_irqrestore(&substream->lock, flags);
        return result;
 }
 EXPORT_SYMBOL(snd_rawmidi_receive);
@@ -1362,20 +1326,15 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
 int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
 {
        struct snd_rawmidi_runtime *runtime;
-       int result;
-       unsigned long flags;
 
-       spin_lock_irqsave(&substream->lock, flags);
+       guard(spinlock_irqsave)(&substream->lock);
        runtime = substream->runtime;
        if (!substream->opened || !runtime || !runtime->buffer) {
                rmidi_dbg(substream->rmidi,
                          "snd_rawmidi_transmit_empty: output is not active!!!\n");
-               result = 1;
-       } else {
-               result = runtime->avail >= runtime->buffer_size;
+               return 1;
        }
-       spin_unlock_irqrestore(&substream->lock, flags);
-       return result;
+       return (runtime->avail >= runtime->buffer_size);
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
 
@@ -1449,16 +1408,10 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
 int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
                              unsigned char *buffer, int count)
 {
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&substream->lock, flags);
+       guard(spinlock_irqsave)(&substream->lock);
        if (!substream->opened || !substream->runtime)
-               result = -EBADFD;
-       else
-               result = __snd_rawmidi_transmit_peek(substream, buffer, count);
-       spin_unlock_irqrestore(&substream->lock, flags);
-       return result;
+               return -EBADFD;
+       return __snd_rawmidi_transmit_peek(substream, buffer, count);
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
 
@@ -1505,16 +1458,10 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
  */
 int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
 {
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&substream->lock, flags);
+       guard(spinlock_irqsave)(&substream->lock);
        if (!substream->opened || !substream->runtime)
-               result = -EBADFD;
-       else
-               result = __snd_rawmidi_transmit_ack(substream, count);
-       spin_unlock_irqrestore(&substream->lock, flags);
-       return result;
+               return -EBADFD;
+       return __snd_rawmidi_transmit_ack(substream, count);
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
 
@@ -1531,21 +1478,13 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
 int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
                         unsigned char *buffer, int count)
 {
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&substream->lock, flags);
+       guard(spinlock_irqsave)(&substream->lock);
        if (!substream->opened)
-               result = -EBADFD;
-       else {
-               count = __snd_rawmidi_transmit_peek(substream, buffer, count);
-               if (count <= 0)
-                       result = count;
-               else
-                       result = __snd_rawmidi_transmit_ack(substream, count);
-       }
-       spin_unlock_irqrestore(&substream->lock, flags);
-       return result;
+               return -EBADFD;
+       count = __snd_rawmidi_transmit_peek(substream, buffer, count);
+       if (count <= 0)
+               return count;
+       return __snd_rawmidi_transmit_ack(substream, count);
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit);
 
@@ -1558,17 +1497,15 @@ EXPORT_SYMBOL(snd_rawmidi_transmit);
 int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
 {
        struct snd_rawmidi_runtime *runtime;
-       unsigned long flags;
        int count = 0;
 
-       spin_lock_irqsave(&substream->lock, flags);
+       guard(spinlock_irqsave)(&substream->lock);
        runtime = substream->runtime;
        if (substream->opened && runtime &&
            runtime->avail < runtime->buffer_size) {
                count = runtime->buffer_size - runtime->avail;
                __snd_rawmidi_transmit_ack(substream, count);
        }
-       spin_unlock_irqrestore(&substream->lock, flags);
        return count;
 }
 EXPORT_SYMBOL(snd_rawmidi_proceed);
@@ -1772,7 +1709,7 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                            rawmidi_is_ump(rmidi) ? "UMP" : "Legacy");
        if (rmidi->ops && rmidi->ops->proc_read)
                rmidi->ops->proc_read(entry, buffer);
-       mutex_lock(&rmidi->open_mutex);
+       guard(mutex)(&rmidi->open_mutex);
        if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
                list_for_each_entry(substream,
                                    &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
@@ -1787,10 +1724,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                                    "  Owner PID    : %d\n",
                                    pid_vnr(substream->pid));
                                runtime = substream->runtime;
-                               spin_lock_irq(&substream->lock);
-                               buffer_size = runtime->buffer_size;
-                               avail = runtime->avail;
-                               spin_unlock_irq(&substream->lock);
+                               scoped_guard(spinlock_irq, &substream->lock) {
+                                       buffer_size = runtime->buffer_size;
+                                       avail = runtime->avail;
+                               }
                                snd_iprintf(buffer,
                                    "  Mode         : %s\n"
                                    "  Buffer size  : %lu\n"
@@ -1814,11 +1751,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                                            "  Owner PID    : %d\n",
                                            pid_vnr(substream->pid));
                                runtime = substream->runtime;
-                               spin_lock_irq(&substream->lock);
-                               buffer_size = runtime->buffer_size;
-                               avail = runtime->avail;
-                               xruns = runtime->xruns;
-                               spin_unlock_irq(&substream->lock);
+                               scoped_guard(spinlock_irq, &substream->lock) {
+                                       buffer_size = runtime->buffer_size;
+                                       avail = runtime->avail;
+                                       xruns = runtime->xruns;
+                               }
                                snd_iprintf(buffer,
                                            "  Buffer size  : %lu\n"
                                            "  Avail        : %lu\n"
@@ -1835,7 +1772,6 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                        }
                }
        }
-       mutex_unlock(&rmidi->open_mutex);
 }
 
 /*
@@ -2024,12 +1960,12 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
        if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
                return -ENOMEM;
        err = 0;
-       mutex_lock(&register_mutex);
-       if (snd_rawmidi_search(rmidi->card, rmidi->device))
-               err = -EBUSY;
-       else
-               list_add_tail(&rmidi->list, &snd_rawmidi_devices);
-       mutex_unlock(&register_mutex);
+       scoped_guard(mutex, &register_mutex) {
+               if (snd_rawmidi_search(rmidi->card, rmidi->device))
+                       err = -EBUSY;
+               else
+                       list_add_tail(&rmidi->list, &snd_rawmidi_devices);
+       }
        if (err < 0)
                return err;
 
@@ -2102,9 +2038,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
  error_unregister:
        snd_unregister_device(rmidi->dev);
  error:
-       mutex_lock(&register_mutex);
-       list_del(&rmidi->list);
-       mutex_unlock(&register_mutex);
+       scoped_guard(mutex, &register_mutex)
+               list_del(&rmidi->list);
        return err;
 }
 
@@ -2113,8 +2048,8 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
        struct snd_rawmidi *rmidi = device->device_data;
        int dir;
 
-       mutex_lock(&register_mutex);
-       mutex_lock(&rmidi->open_mutex);
+       guard(mutex)(&register_mutex);
+       guard(mutex)(&rmidi->open_mutex);
        wake_up(&rmidi->open_wait);
        list_del_init(&rmidi->list);
        for (dir = 0; dir < 2; dir++) {
@@ -2140,8 +2075,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
        }
 #endif /* CONFIG_SND_OSSEMUL */
        snd_unregister_device(rmidi->dev);
-       mutex_unlock(&rmidi->open_mutex);
-       mutex_unlock(&register_mutex);
        return 0;
 }
 
index c14981daf9432f7218ab1cc03943c9ec9b6536d9..0374bbf51cd4d38af3564d25d82fe27d4ad5a08a 100644 (file)
@@ -71,7 +71,6 @@ config SND_SEQ_UMP
          among legacy and UMP clients.
 
 config SND_SEQ_UMP_CLIENT
-       tristate
        def_tristate SND_UMP
 
 endif # SND_SEQUENCER
index 6c2c4fb9b753786784a967efe926c09a4f603d20..f0e964b19af7aea9122a8df915f6195644111552 100644 (file)
@@ -163,6 +163,6 @@ snd_seq_oss_fill_addr(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
 
 
 /* misc. functions for proc interface */
-char *enabled_str(int bool);
+char *enabled_str(bool b);
 
 #endif /* __SEQ_OSS_DEVICE_H */
index 42d4e7535a820456b1f4f92fa4a12c81fa07e60d..676246fa02f15edc8fa0e5bdaaf827cc1cd6810f 100644 (file)
@@ -63,20 +63,18 @@ int __init
 snd_seq_oss_create_client(void)
 {
        int rc;
-       struct snd_seq_port_info *port;
+       struct snd_seq_port_info *port __free(kfree) = NULL;
        struct snd_seq_port_callback port_callback;
 
        port = kzalloc(sizeof(*port), GFP_KERNEL);
-       if (!port) {
-               rc = -ENOMEM;
-               goto __error;
-       }
+       if (!port)
+               return -ENOMEM;
 
        /* create ALSA client */
        rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
                                          "OSS sequencer");
        if (rc < 0)
-               goto __error;
+               return rc;
 
        system_client = rc;
 
@@ -104,14 +102,11 @@ snd_seq_oss_create_client(void)
                subs.dest.port = system_port;
                call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
        }
-       rc = 0;
 
        /* look up midi devices */
        schedule_work(&async_lookup_work);
 
- __error:
-       kfree(port);
-       return rc;
+       return 0;
 }
 
 
@@ -455,9 +450,9 @@ snd_seq_oss_reset(struct seq_oss_devinfo *dp)
  * misc. functions for proc interface
  */
 char *
-enabled_str(int bool)
+enabled_str(bool b)
 {
-       return bool ? "enabled" : "disabled";
+       return b ? "enabled" : "disabled";
 }
 
 static const char *
index f2940b29595f0921ad97e94f090e33561ac6d3cd..f8e247d9e5c99fd1773612c53d3344fbe71e0830 100644 (file)
@@ -64,16 +64,13 @@ static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
 int
 snd_seq_oss_midi_lookup_ports(int client)
 {
-       struct snd_seq_client_info *clinfo;
-       struct snd_seq_port_info *pinfo;
+       struct snd_seq_client_info *clinfo __free(kfree) = NULL;
+       struct snd_seq_port_info *pinfo __free(kfree) = NULL;
 
        clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL);
        pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
-       if (! clinfo || ! pinfo) {
-               kfree(clinfo);
-               kfree(pinfo);
+       if (!clinfo || !pinfo)
                return -ENOMEM;
-       }
        clinfo->client = -1;
        while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
                if (clinfo->client == client)
@@ -83,8 +80,6 @@ snd_seq_oss_midi_lookup_ports(int client)
                while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
                        snd_seq_oss_midi_check_new_port(pinfo);
        }
-       kfree(clinfo);
-       kfree(pinfo);
        return 0;
 }
 
index 1e35bf086a51da5a41884fb3fc2c3bf7b146b955..643af4c1e838669a2fe45c9ecfb4072d166c917b 100644 (file)
@@ -31,8 +31,8 @@ struct snd_seq_port_info32 {
 static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned int cmd,
                                        struct snd_seq_port_info32 __user *data32)
 {
-       int err = -EFAULT;
-       struct snd_seq_port_info *data;
+       struct snd_seq_port_info *data __free(kfree) = NULL;
+       int err;
 
        data = kmalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
@@ -41,20 +41,18 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned
        if (copy_from_user(data, data32, sizeof(*data32)) ||
            get_user(data->flags, &data32->flags) ||
            get_user(data->time_queue, &data32->time_queue))
-               goto error;
+               return -EFAULT;
        data->kernel = NULL;
 
        err = snd_seq_kernel_client_ctl(client->number, cmd, data);
        if (err < 0)
-               goto error;
+               return err;
 
        if (copy_to_user(data32, data, sizeof(*data32)) ||
            put_user(data->flags, &data32->flags) ||
            put_user(data->time_queue, &data32->time_queue))
-               err = -EFAULT;
+               return -EFAULT;
 
- error:
-       kfree(data);
        return err;
 }
 
index f8e02e98709abe12a5ff6336958cc6e16f9f10ca..3a10b081f129c30d677a9e834a7477a065fd8044 100644 (file)
@@ -88,12 +88,11 @@ void snd_seq_fifo_clear(struct snd_seq_fifo *f)
        atomic_set(&f->overflow, 0);
 
        snd_use_lock_sync(&f->use_lock);
-       spin_lock_irq(&f->lock);
+       guard(spinlock_irq)(&f->lock);
        /* drain the fifo */
        while ((cell = fifo_cell_out(f)) != NULL) {
                snd_seq_cell_free(cell);
        }
-       spin_unlock_irq(&f->lock);
 }
 
 
@@ -102,7 +101,6 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
                          struct snd_seq_event *event)
 {
        struct snd_seq_event_cell *cell;
-       unsigned long flags;
        int err;
 
        if (snd_BUG_ON(!f))
@@ -118,15 +116,15 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
        }
                
        /* append new cells to fifo */
-       spin_lock_irqsave(&f->lock, flags);
-       if (f->tail != NULL)
-               f->tail->next = cell;
-       f->tail = cell;
-       if (f->head == NULL)
-               f->head = cell;
-       cell->next = NULL;
-       f->cells++;
-       spin_unlock_irqrestore(&f->lock, flags);
+       scoped_guard(spinlock_irqsave, &f->lock) {
+               if (f->tail != NULL)
+                       f->tail->next = cell;
+               f->tail = cell;
+               if (f->head == NULL)
+                       f->head = cell;
+               cell->next = NULL;
+               f->cells++;
+       }
 
        /* wakeup client */
        if (waitqueue_active(&f->input_sleep))
@@ -199,16 +197,13 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
 void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
                               struct snd_seq_event_cell *cell)
 {
-       unsigned long flags;
-
        if (cell) {
-               spin_lock_irqsave(&f->lock, flags);
+               guard(spinlock_irqsave)(&f->lock);
                cell->next = f->head;
                f->head = cell;
                if (!f->tail)
                        f->tail = cell;
                f->cells++;
-               spin_unlock_irqrestore(&f->lock, flags);
        }
 }
 
@@ -239,17 +234,17 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
                return -ENOMEM;
        }
 
-       spin_lock_irq(&f->lock);
-       /* remember old pool */
-       oldpool = f->pool;
-       oldhead = f->head;
-       /* exchange pools */
-       f->pool = newpool;
-       f->head = NULL;
-       f->tail = NULL;
-       f->cells = 0;
-       /* NOTE: overflow flag is not cleared */
-       spin_unlock_irq(&f->lock);
+       scoped_guard(spinlock_irq, &f->lock) {
+               /* remember old pool */
+               oldpool = f->pool;
+               oldhead = f->head;
+               /* exchange pools */
+               f->pool = newpool;
+               f->head = NULL;
+               f->tail = NULL;
+               f->cells = 0;
+               /* NOTE: overflow flag is not cleared */
+       }
 
        /* close the old pool and wait until all users are gone */
        snd_seq_pool_mark_closing(oldpool);
@@ -268,16 +263,14 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
 /* get the number of unused cells safely */
 int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
 {
-       unsigned long flags;
        int cells;
 
        if (!f)
                return 0;
 
        snd_use_lock_use(&f->use_lock);
-       spin_lock_irqsave(&f->lock, flags);
-       cells = snd_seq_unused_cells(f->pool);
-       spin_unlock_irqrestore(&f->lock, flags);
+       scoped_guard(spinlock_irqsave, &f->lock)
+               cells = snd_seq_unused_cells(f->pool);
        snd_use_lock_free(&f->use_lock);
        return cells;
 }
index e705e753811895f2aa4ff45e9bac9c3711bc8ac0..20155e3e87c6ac1d51c2598e8ce979ebe9499e99 100644 (file)
@@ -232,7 +232,6 @@ static inline void free_cell(struct snd_seq_pool *pool,
 
 void snd_seq_cell_free(struct snd_seq_event_cell * cell)
 {
-       unsigned long flags;
        struct snd_seq_pool *pool;
 
        if (snd_BUG_ON(!cell))
@@ -241,7 +240,7 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
        if (snd_BUG_ON(!pool))
                return;
 
-       spin_lock_irqsave(&pool->lock, flags);
+       guard(spinlock_irqsave)(&pool->lock);
        free_cell(pool, cell);
        if (snd_seq_ev_is_variable(&cell->event)) {
                if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) {
@@ -259,7 +258,6 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
                if (snd_seq_output_ok(pool))
                        wake_up(&pool->output_sleep);
        }
-       spin_unlock_irqrestore(&pool->lock, flags);
 }
 
 
@@ -449,9 +447,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
                return -ENOMEM;
 
        /* add new cells to the free cell list */
-       spin_lock_irq(&pool->lock);
+       guard(spinlock_irq)(&pool->lock);
        if (pool->ptr) {
-               spin_unlock_irq(&pool->lock);
                kvfree(cellptr);
                return 0;
        }
@@ -470,20 +467,16 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
        /* init statistics */
        pool->max_used = 0;
        pool->total_elements = pool->size;
-       spin_unlock_irq(&pool->lock);
        return 0;
 }
 
 /* refuse the further insertion to the pool */
 void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
 {
-       unsigned long flags;
-
        if (snd_BUG_ON(!pool))
                return;
-       spin_lock_irqsave(&pool->lock, flags);
+       guard(spinlock_irqsave)(&pool->lock);
        pool->closing = 1;
-       spin_unlock_irqrestore(&pool->lock, flags);
 }
 
 /* remove events */
@@ -502,18 +495,17 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
                schedule_timeout_uninterruptible(1);
        
        /* release all resources */
-       spin_lock_irq(&pool->lock);
-       ptr = pool->ptr;
-       pool->ptr = NULL;
-       pool->free = NULL;
-       pool->total_elements = 0;
-       spin_unlock_irq(&pool->lock);
+       scoped_guard(spinlock_irq, &pool->lock) {
+               ptr = pool->ptr;
+               pool->ptr = NULL;
+               pool->free = NULL;
+               pool->total_elements = 0;
+       }
 
        kvfree(ptr);
 
-       spin_lock_irq(&pool->lock);
+       guard(spinlock_irq)(&pool->lock);
        pool->closing = 0;
-       spin_unlock_irq(&pool->lock);
 
        return 0;
 }
index 18320a248aa7daa080df9499668c400f4da22066..ba52a77eda3828a44e1ab9da53c78d4e968b5ab7 100644 (file)
@@ -113,6 +113,12 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
        return 0;
 }
 
+/* callback for snd_seq_dump_var_event(), bridging to dump_midi() */
+static int __dump_midi(void *ptr, void *buf, int count)
+{
+       return dump_midi(ptr, buf, count);
+}
+
 static int event_process_midi(struct snd_seq_event *ev, int direct,
                              void *private_data, int atomic, int hop)
 {
@@ -132,7 +138,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
                        pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
                        return 0;
                }
-               snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
+               snd_seq_dump_var_event(ev, __dump_midi, substream);
                snd_midi_event_reset_decode(msynth->parser);
        } else {
                if (msynth->parser == NULL)
@@ -264,8 +270,8 @@ snd_seq_midisynth_probe(struct device *_dev)
        struct snd_seq_device *dev = to_seq_dev(_dev);
        struct seq_midisynth_client *client;
        struct seq_midisynth *msynth, *ms;
-       struct snd_seq_port_info *port;
-       struct snd_rawmidi_info *info;
+       struct snd_seq_port_info *port __free(kfree) = NULL;
+       struct snd_rawmidi_info *info __free(kfree) = NULL;
        struct snd_rawmidi *rmidi = dev->private_data;
        int newclient = 0;
        unsigned int p, ports;
@@ -291,31 +297,24 @@ snd_seq_midisynth_probe(struct device *_dev)
        ports = output_count;
        if (ports < input_count)
                ports = input_count;
-       if (ports == 0) {
-               kfree(info);
+       if (ports == 0)
                return -ENODEV;
-       }
        if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
                ports = 256 / SNDRV_RAWMIDI_DEVICES;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        client = synths[card->number];
        if (client == NULL) {
                newclient = 1;
                client = kzalloc(sizeof(*client), GFP_KERNEL);
-               if (client == NULL) {
-                       mutex_unlock(&register_mutex);
-                       kfree(info);
+               if (client == NULL)
                        return -ENOMEM;
-               }
                client->seq_client =
                        snd_seq_create_kernel_client(
                                card, 0, "%s", card->shortname[0] ?
                                (const char *)card->shortname : "External MIDI");
                if (client->seq_client < 0) {
                        kfree(client);
-                       mutex_unlock(&register_mutex);
-                       kfree(info);
                        return -ENOMEM;
                }
        }
@@ -396,9 +395,6 @@ snd_seq_midisynth_probe(struct device *_dev)
        client->num_ports++;
        if (newclient)
                synths[card->number] = client;
-       mutex_unlock(&register_mutex);
-       kfree(info);
-       kfree(port);
        return 0;       /* success */
 
       __nomem:
@@ -411,9 +407,6 @@ snd_seq_midisynth_probe(struct device *_dev)
                snd_seq_delete_kernel_client(client->seq_client);
                kfree(client);
        }
-       kfree(info);
-       kfree(port);
-       mutex_unlock(&register_mutex);
        return -ENOMEM;
 }
 
@@ -427,12 +420,10 @@ snd_seq_midisynth_remove(struct device *_dev)
        struct snd_card *card = dev->card;
        int device = dev->device, p, ports;
        
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        client = synths[card->number];
-       if (client == NULL || client->ports[device] == NULL) {
-               mutex_unlock(&register_mutex);
+       if (client == NULL || client->ports[device] == NULL)
                return -ENODEV;
-       }
        ports = client->ports_per_device[device];
        client->ports_per_device[device] = 0;
        msynth = client->ports[device];
@@ -446,7 +437,6 @@ snd_seq_midisynth_remove(struct device *_dev)
                synths[card->number] = NULL;
                kfree(client);
        }
-       mutex_unlock(&register_mutex);
        return 0;
 }
 
index 7511462fe0718604266381acd69d1e4ba1e2d987..fa9dfc53c3fcc65c07cfde3a2a2276aeda08d1a4 100644 (file)
@@ -144,21 +144,15 @@ static inline void reset_encode(struct snd_midi_event *dev)
 
 void snd_midi_event_reset_encode(struct snd_midi_event *dev)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->lock, flags);
+       guard(spinlock_irqsave)(&dev->lock);
        reset_encode(dev);
-       spin_unlock_irqrestore(&dev->lock, flags);
 }
 EXPORT_SYMBOL(snd_midi_event_reset_encode);
 
 void snd_midi_event_reset_decode(struct snd_midi_event *dev)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->lock, flags);
+       guard(spinlock_irqsave)(&dev->lock);
        dev->lastcmd = 0xff;
-       spin_unlock_irqrestore(&dev->lock, flags);
 }
 EXPORT_SYMBOL(snd_midi_event_reset_decode);
 
@@ -177,7 +171,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
                                struct snd_seq_event *ev)
 {
        bool rc = false;
-       unsigned long flags;
 
        if (c >= MIDI_CMD_COMMON_CLOCK) {
                /* real-time event */
@@ -187,7 +180,7 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
                return ev->type != SNDRV_SEQ_EVENT_NONE;
        }
 
-       spin_lock_irqsave(&dev->lock, flags);
+       guard(spinlock_irqsave)(&dev->lock);
        if ((c & 0x80) &&
            (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
                /* new command */
@@ -236,7 +229,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
                }
        }
 
-       spin_unlock_irqrestore(&dev->lock, flags);
        return rc;
 }
 EXPORT_SYMBOL(snd_midi_event_encode_byte);
index f3f14ff0f80f0c533e7f9df37929d6d88cb21470..ca631ca4f2c64ebf46292b99a2c6c48128e293cf 100644 (file)
@@ -48,17 +48,15 @@ struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
 
        if (client == NULL)
                return NULL;
-       read_lock(&client->ports_lock);
+       guard(read_lock)(&client->ports_lock);
        list_for_each_entry(port, &client->ports_list_head, list) {
                if (port->addr.port == num) {
                        if (port->closing)
                                break; /* deleting now */
                        snd_use_lock_use(&port->use_lock);
-                       read_unlock(&client->ports_lock);
                        return port;
                }
        }
-       read_unlock(&client->ports_lock);
        return NULL;            /* not found */
 }
 
@@ -73,7 +71,7 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
 
        num = pinfo->addr.port;
        found = NULL;
-       read_lock(&client->ports_lock);
+       guard(read_lock)(&client->ports_lock);
        list_for_each_entry(port, &client->ports_list_head, list) {
                if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) &&
                    !check_inactive)
@@ -93,7 +91,6 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
                else
                        snd_use_lock_use(&found->use_lock);
        }
-       read_unlock(&client->ports_lock);
        return found;
 }
 
@@ -145,13 +142,12 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
        snd_use_lock_use(&new_port->use_lock);
 
        num = max(port, 0);
-       mutex_lock(&client->ports_mutex);
-       write_lock_irq(&client->ports_lock);
+       guard(mutex)(&client->ports_mutex);
+       guard(write_lock_irq)(&client->ports_lock);
        list_for_each_entry(p, &client->ports_list_head, list) {
                if (p->addr.port == port) {
                        kfree(new_port);
-                       num = -EBUSY;
-                       goto unlock;
+                       return -EBUSY;
                }
                if (p->addr.port > num)
                        break;
@@ -164,9 +160,6 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
        new_port->addr.port = num;      /* store the port number in the port */
        sprintf(new_port->name, "port-%d", num);
        *port_ret = new_port;
- unlock:
-       write_unlock_irq(&client->ports_lock);
-       mutex_unlock(&client->ports_mutex);
 
        return num;
 }
@@ -281,19 +274,18 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
 {
        struct snd_seq_client_port *found = NULL, *p;
 
-       mutex_lock(&client->ports_mutex);
-       write_lock_irq(&client->ports_lock);
-       list_for_each_entry(p, &client->ports_list_head, list) {
-               if (p->addr.port == port) {
-                       /* ok found.  delete from the list at first */
-                       list_del(&p->list);
-                       client->num_ports--;
-                       found = p;
-                       break;
+       scoped_guard(mutex, &client->ports_mutex) {
+               guard(write_lock_irq)(&client->ports_lock);
+               list_for_each_entry(p, &client->ports_list_head, list) {
+                       if (p->addr.port == port) {
+                               /* ok found.  delete from the list at first */
+                               list_del(&p->list);
+                               client->num_ports--;
+                               found = p;
+                               break;
+                       }
                }
        }
-       write_unlock_irq(&client->ports_lock);
-       mutex_unlock(&client->ports_mutex);
        if (found)
                return port_delete(client, found);
        else
@@ -309,16 +301,16 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
        /* move the port list to deleted_list, and
         * clear the port list in the client data.
         */
-       mutex_lock(&client->ports_mutex);
-       write_lock_irq(&client->ports_lock);
-       if (! list_empty(&client->ports_list_head)) {
-               list_add(&deleted_list, &client->ports_list_head);
-               list_del_init(&client->ports_list_head);
-       } else {
-               INIT_LIST_HEAD(&deleted_list);
+       guard(mutex)(&client->ports_mutex);
+       scoped_guard(write_lock_irq, &client->ports_lock) {
+               if (!list_empty(&client->ports_list_head)) {
+                       list_add(&deleted_list, &client->ports_list_head);
+                       list_del_init(&client->ports_list_head);
+               } else {
+                       INIT_LIST_HEAD(&deleted_list);
+               }
+               client->num_ports = 0;
        }
-       client->num_ports = 0;
-       write_unlock_irq(&client->ports_lock);
 
        /* remove each port in deleted_list */
        list_for_each_entry_safe(port, tmp, &deleted_list, list) {
@@ -326,7 +318,6 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
                snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
                port_delete(client, port);
        }
-       mutex_unlock(&client->ports_mutex);
        return 0;
 }
 
@@ -506,42 +497,37 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
        int err;
 
        grp = is_src ? &port->c_src : &port->c_dest;
-       err = -EBUSY;
-       down_write(&grp->list_mutex);
+       guard(rwsem_write)(&grp->list_mutex);
        if (exclusive) {
                if (!list_empty(&grp->list_head))
-                       goto __error;
+                       return -EBUSY;
        } else {
                if (grp->exclusive)
-                       goto __error;
+                       return -EBUSY;
                /* check whether already exists */
                list_for_each(p, &grp->list_head) {
                        s = get_subscriber(p, is_src);
                        if (match_subs_info(&subs->info, &s->info))
-                               goto __error;
+                               return -EBUSY;
                }
        }
 
        err = subscribe_port(client, port, grp, &subs->info, ack);
        if (err < 0) {
                grp->exclusive = 0;
-               goto __error;
+               return err;
        }
 
        /* add to list */
-       write_lock_irq(&grp->list_lock);
+       guard(write_lock_irq)(&grp->list_lock);
        if (is_src)
                list_add_tail(&subs->src_list, &grp->list_head);
        else
                list_add_tail(&subs->dest_list, &grp->list_head);
        grp->exclusive = exclusive;
        atomic_inc(&subs->ref_count);
-       write_unlock_irq(&grp->list_lock);
-       err = 0;
 
- __error:
-       up_write(&grp->list_mutex);
-       return err;
+       return 0;
 }
 
 /* called with grp->list_mutex held */
@@ -556,12 +542,12 @@ static void __delete_and_unsubscribe_port(struct snd_seq_client *client,
 
        grp = is_src ? &port->c_src : &port->c_dest;
        list = is_src ? &subs->src_list : &subs->dest_list;
-       write_lock_irq(&grp->list_lock);
-       empty = list_empty(list);
-       if (!empty)
-               list_del_init(list);
-       grp->exclusive = 0;
-       write_unlock_irq(&grp->list_lock);
+       scoped_guard(write_lock_irq, &grp->list_lock) {
+               empty = list_empty(list);
+               if (!empty)
+                       list_del_init(list);
+               grp->exclusive = 0;
+       }
 
        if (!empty)
                unsubscribe_port(client, port, grp, &subs->info, ack);
@@ -575,9 +561,8 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
        struct snd_seq_port_subs_info *grp;
 
        grp = is_src ? &port->c_src : &port->c_dest;
-       down_write(&grp->list_mutex);
+       guard(rwsem_write)(&grp->list_mutex);
        __delete_and_unsubscribe_port(client, port, subs, is_src, ack);
-       up_write(&grp->list_mutex);
 }
 
 /* connect two ports */
@@ -639,18 +624,18 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
        /* always start from deleting the dest port for avoiding concurrent
         * deletions
         */
-       down_write(&dest->list_mutex);
-       /* look for the connection */
-       list_for_each_entry(subs, &dest->list_head, dest_list) {
-               if (match_subs_info(info, &subs->info)) {
-                       __delete_and_unsubscribe_port(dest_client, dest_port,
-                                                     subs, false,
-                                                     connector->number != dest_client->number);
-                       err = 0;
-                       break;
+       scoped_guard(rwsem_write, &dest->list_mutex) {
+               /* look for the connection */
+               list_for_each_entry(subs, &dest->list_head, dest_list) {
+                       if (match_subs_info(info, &subs->info)) {
+                               __delete_and_unsubscribe_port(dest_client, dest_port,
+                                                             subs, false,
+                                                             connector->number != dest_client->number);
+                               err = 0;
+                               break;
+                       }
                }
        }
-       up_write(&dest->list_mutex);
        if (err < 0)
                return err;
 
@@ -669,7 +654,7 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
        struct snd_seq_subscribers *s;
        int err = -ENOENT;
 
-       down_read(&src_grp->list_mutex);
+       guard(rwsem_read)(&src_grp->list_mutex);
        list_for_each_entry(s, &src_grp->list_head, src_list) {
                if (addr_match(dest_addr, &s->info.dest)) {
                        *subs = s->info;
@@ -677,7 +662,6 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
                        break;
                }
        }
-       up_read(&src_grp->list_mutex);
        return err;
 }
 
index 1d857981e8764ce506df3457e97ce44eddb593fa..e649485a877222a58c93468df825d43051be608c 100644 (file)
@@ -132,7 +132,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
                          struct snd_seq_event_cell * cell)
 {
        struct snd_seq_event_cell *cur, *prev;
-       unsigned long flags;
        int count;
        int prior;
 
@@ -142,7 +141,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
        /* check flags */
        prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
 
-       spin_lock_irqsave(&f->lock, flags);
+       guard(spinlock_irqsave)(&f->lock);
 
        /* check if this element needs to inserted at the end (ie. ordered 
           data is inserted) This will be very likeley if a sequencer 
@@ -154,7 +153,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
                        f->tail = cell;
                        cell->next = NULL;
                        f->cells++;
-                       spin_unlock_irqrestore(&f->lock, flags);
                        return 0;
                }
        }
@@ -179,7 +177,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
                prev = cur;
                cur = cur->next;
                if (! --count) {
-                       spin_unlock_irqrestore(&f->lock, flags);
                        pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
                        return -EINVAL;
                }
@@ -195,7 +192,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
        if (cur == NULL) /* reached end of the list */
                f->tail = cell;
        f->cells++;
-       spin_unlock_irqrestore(&f->lock, flags);
        return 0;
 }
 
@@ -213,14 +209,13 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
                                                  void *current_time)
 {
        struct snd_seq_event_cell *cell;
-       unsigned long flags;
 
        if (f == NULL) {
                pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
                return NULL;
        }
-       spin_lock_irqsave(&f->lock, flags);
 
+       guard(spinlock_irqsave)(&f->lock);
        cell = f->head;
        if (cell && current_time && !event_is_ready(&cell->event, current_time))
                cell = NULL;
@@ -235,7 +230,6 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
                f->cells--;
        }
 
-       spin_unlock_irqrestore(&f->lock, flags);
        return cell;
 }
 
@@ -249,73 +243,43 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
        return f->cells;
 }
 
-static inline int prioq_match(struct snd_seq_event_cell *cell,
-                             int client, int timestamp)
-{
-       if (cell->event.source.client == client ||
-           cell->event.dest.client == client)
-               return 1;
-       if (!timestamp)
-               return 0;
-       switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
-       case SNDRV_SEQ_TIME_STAMP_TICK:
-               if (cell->event.time.tick)
-                       return 1;
-               break;
-       case SNDRV_SEQ_TIME_STAMP_REAL:
-               if (cell->event.time.time.tv_sec ||
-                   cell->event.time.time.tv_nsec)
-                       return 1;
-               break;
-       }
-       return 0;
-}
-
-/* remove cells for left client */
-void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
+/* remove cells matching with the condition */
+static void prioq_remove_cells(struct snd_seq_prioq *f,
+                              bool (*match)(struct snd_seq_event_cell *cell,
+                                            void *arg),
+                              void *arg)
 {
        register struct snd_seq_event_cell *cell, *next;
-       unsigned long flags;
        struct snd_seq_event_cell *prev = NULL;
        struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
 
        /* collect all removed cells */
-       spin_lock_irqsave(&f->lock, flags);
-       cell = f->head;
-       while (cell) {
-               next = cell->next;
-               if (prioq_match(cell, client, timestamp)) {
+       scoped_guard(spinlock_irqsave, &f->lock) {
+               for (cell = f->head; cell; cell = next) {
+                       next = cell->next;
+                       if (!match(cell, arg)) {
+                               prev = cell;
+                               continue;
+                       }
+
                        /* remove cell from prioq */
-                       if (cell == f->head) {
+                       if (cell == f->head)
                                f->head = cell->next;
-                       } else {
+                       else
                                prev->next = cell->next;
-                       }
                        if (cell == f->tail)
                                f->tail = cell->next;
                        f->cells--;
+
                        /* add cell to free list */
                        cell->next = NULL;
-                       if (freefirst == NULL) {
+                       if (freefirst == NULL)
                                freefirst = cell;
-                       } else {
+                       else
                                freeprev->next = cell;
-                       }
                        freeprev = cell;
-               } else {
-#if 0
-                       pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
-                              "client = %i\n",
-                               cell->event.type,
-                               cell->event.source.client,
-                               cell->event.dest.client,
-                               client);
-#endif
-                       prev = cell;
                }
-               cell = next;            
        }
-       spin_unlock_irqrestore(&f->lock, flags);        
 
        /* remove selected cells */
        while (freefirst) {
@@ -325,22 +289,68 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
        }
 }
 
-static int prioq_remove_match(struct snd_seq_remove_events *info,
-                             struct snd_seq_event *ev)
+struct prioq_match_arg {
+       int client;
+       int timestamp;
+};
+
+static inline bool prioq_match(struct snd_seq_event_cell *cell, void *arg)
+{
+       struct prioq_match_arg *v = arg;
+
+       if (cell->event.source.client == v->client ||
+           cell->event.dest.client == v->client)
+               return true;
+       if (!v->timestamp)
+               return false;
+       switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
+       case SNDRV_SEQ_TIME_STAMP_TICK:
+               if (cell->event.time.tick)
+                       return true;
+               break;
+       case SNDRV_SEQ_TIME_STAMP_REAL:
+               if (cell->event.time.time.tv_sec ||
+                   cell->event.time.time.tv_nsec)
+                       return true;
+               break;
+       }
+       return false;
+}
+
+/* remove cells for left client */
+void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp)
 {
+       struct prioq_match_arg arg = { client, timestamp };
+
+       return prioq_remove_cells(f, prioq_match, &arg);
+}
+
+struct prioq_remove_match_arg {
+       int client;
+       struct snd_seq_remove_events *info;
+};
+
+static bool prioq_remove_match(struct snd_seq_event_cell *cell, void *arg)
+{
+       struct prioq_remove_match_arg *v = arg;
+       struct snd_seq_event *ev = &cell->event;
+       struct snd_seq_remove_events *info = v->info;
        int res;
 
+       if (ev->source.client != v->client)
+               return false;
+
        if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
                if (ev->dest.client != info->dest.client ||
                                ev->dest.port != info->dest.port)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
                if (! snd_seq_ev_is_channel_type(ev))
-                       return 0;
+                       return false;
                /* data.note.channel and data.control.channel are identical */
                if (ev->data.note.channel != info->channel)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) {
                if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
@@ -348,7 +358,7 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
                else
                        res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
                if (!res)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
                if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
@@ -356,81 +366,35 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
                else
                        res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
                if (res)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
                if (ev->type != info->type)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
                /* Do not remove off events */
                switch (ev->type) {
                case SNDRV_SEQ_EVENT_NOTEOFF:
                /* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
-                       return 0;
+                       return false;
                default:
                        break;
                }
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
                if (info->tag != ev->tag)
-                       return 0;
+                       return false;
        }
 
-       return 1;
+       return true;
 }
 
 /* remove cells matching remove criteria */
 void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
                                 struct snd_seq_remove_events *info)
 {
-       struct snd_seq_event_cell *cell, *next;
-       unsigned long flags;
-       struct snd_seq_event_cell *prev = NULL;
-       struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
-
-       /* collect all removed cells */
-       spin_lock_irqsave(&f->lock, flags);
-       cell = f->head;
-
-       while (cell) {
-               next = cell->next;
-               if (cell->event.source.client == client &&
-                       prioq_remove_match(info, &cell->event)) {
+       struct prioq_remove_match_arg arg = { client, info };
 
-                       /* remove cell from prioq */
-                       if (cell == f->head) {
-                               f->head = cell->next;
-                       } else {
-                               prev->next = cell->next;
-                       }
-
-                       if (cell == f->tail)
-                               f->tail = cell->next;
-                       f->cells--;
-
-                       /* add cell to free list */
-                       cell->next = NULL;
-                       if (freefirst == NULL) {
-                               freefirst = cell;
-                       } else {
-                               freeprev->next = cell;
-                       }
-
-                       freeprev = cell;
-               } else {
-                       prev = cell;
-               }
-               cell = next;            
-       }
-       spin_unlock_irqrestore(&f->lock, flags);        
-
-       /* remove selected cells */
-       while (freefirst) {
-               freenext = freefirst->next;
-               snd_seq_cell_free(freefirst);
-               freefirst = freenext;
-       }
+       return prioq_remove_cells(f, prioq_remove_match, &arg);
 }
-
-
index bc933104c3eea64556bf92bc041d869fc629137e..500ee6b19c717746af1b3f723d4e667825813b33 100644 (file)
@@ -50,43 +50,35 @@ int snd_seq_queue_get_cur_queues(void)
 static int queue_list_add(struct snd_seq_queue *q)
 {
        int i;
-       unsigned long flags;
 
-       spin_lock_irqsave(&queue_list_lock, flags);
+       guard(spinlock_irqsave)(&queue_list_lock);
        for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
                if (! queue_list[i]) {
                        queue_list[i] = q;
                        q->queue = i;
                        num_queues++;
-                       spin_unlock_irqrestore(&queue_list_lock, flags);
                        return i;
                }
        }
-       spin_unlock_irqrestore(&queue_list_lock, flags);
        return -1;
 }
 
 static struct snd_seq_queue *queue_list_remove(int id, int client)
 {
        struct snd_seq_queue *q;
-       unsigned long flags;
 
-       spin_lock_irqsave(&queue_list_lock, flags);
+       guard(spinlock_irqsave)(&queue_list_lock);
        q = queue_list[id];
        if (q) {
-               spin_lock(&q->owner_lock);
+               guard(spinlock)(&q->owner_lock);
                if (q->owner == client) {
                        /* found */
                        q->klocked = 1;
-                       spin_unlock(&q->owner_lock);
                        queue_list[id] = NULL;
                        num_queues--;
-                       spin_unlock_irqrestore(&queue_list_lock, flags);
                        return q;
                }
-               spin_unlock(&q->owner_lock);
        }
-       spin_unlock_irqrestore(&queue_list_lock, flags);
        return NULL;
 }
 
@@ -203,15 +195,13 @@ int snd_seq_queue_delete(int client, int queueid)
 struct snd_seq_queue *queueptr(int queueid)
 {
        struct snd_seq_queue *q;
-       unsigned long flags;
 
        if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
                return NULL;
-       spin_lock_irqsave(&queue_list_lock, flags);
+       guard(spinlock_irqsave)(&queue_list_lock);
        q = queue_list[queueid];
        if (q)
                snd_use_lock_use(&q->use_lock);
-       spin_unlock_irqrestore(&queue_list_lock, flags);
        return q;
 }
 
@@ -239,7 +229,6 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name)
 
 void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
 {
-       unsigned long flags;
        struct snd_seq_event_cell *cell;
        snd_seq_tick_time_t cur_tick;
        snd_seq_real_time_t cur_time;
@@ -249,14 +238,13 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
                return;
 
        /* make this function non-reentrant */
-       spin_lock_irqsave(&q->check_lock, flags);
-       if (q->check_blocked) {
-               q->check_again = 1;
-               spin_unlock_irqrestore(&q->check_lock, flags);
-               return;         /* other thread is already checking queues */
+       scoped_guard(spinlock_irqsave, &q->check_lock) {
+               if (q->check_blocked) {
+                       q->check_again = 1;
+                       return; /* other thread is already checking queues */
+               }
+               q->check_blocked = 1;
        }
-       q->check_blocked = 1;
-       spin_unlock_irqrestore(&q->check_lock, flags);
 
       __again:
        /* Process tick queue... */
@@ -283,16 +271,14 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
 
  out:
        /* free lock */
-       spin_lock_irqsave(&q->check_lock, flags);
-       if (q->check_again) {
-               q->check_again = 0;
-               if (processed < MAX_CELL_PROCESSES_IN_QUEUE) {
-                       spin_unlock_irqrestore(&q->check_lock, flags);
-                       goto __again;
+       scoped_guard(spinlock_irqsave, &q->check_lock) {
+               if (q->check_again) {
+                       q->check_again = 0;
+                       if (processed < MAX_CELL_PROCESSES_IN_QUEUE)
+                               goto __again;
                }
+               q->check_blocked = 0;
        }
-       q->check_blocked = 0;
-       spin_unlock_irqrestore(&q->check_lock, flags);
 }
 
 
@@ -361,25 +347,20 @@ static inline int check_access(struct snd_seq_queue *q, int client)
  */
 static int queue_access_lock(struct snd_seq_queue *q, int client)
 {
-       unsigned long flags;
        int access_ok;
        
-       spin_lock_irqsave(&q->owner_lock, flags);
+       guard(spinlock_irqsave)(&q->owner_lock);
        access_ok = check_access(q, client);
        if (access_ok)
                q->klocked = 1;
-       spin_unlock_irqrestore(&q->owner_lock, flags);
        return access_ok;
 }
 
 /* unlock the queue */
 static inline void queue_access_unlock(struct snd_seq_queue *q)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&q->owner_lock, flags);
+       guard(spinlock_irqsave)(&q->owner_lock);
        q->klocked = 0;
-       spin_unlock_irqrestore(&q->owner_lock, flags);
 }
 
 /* exported - only checking permission */
@@ -387,13 +368,11 @@ int snd_seq_queue_check_access(int queueid, int client)
 {
        struct snd_seq_queue *q = queueptr(queueid);
        int access_ok;
-       unsigned long flags;
 
        if (! q)
                return 0;
-       spin_lock_irqsave(&q->owner_lock, flags);
-       access_ok = check_access(q, client);
-       spin_unlock_irqrestore(&q->owner_lock, flags);
+       scoped_guard(spinlock_irqsave, &q->owner_lock)
+               access_ok = check_access(q, client);
        queuefree(q);
        return access_ok;
 }
@@ -406,7 +385,6 @@ int snd_seq_queue_check_access(int queueid, int client)
 int snd_seq_queue_set_owner(int queueid, int client, int locked)
 {
        struct snd_seq_queue *q = queueptr(queueid);
-       unsigned long flags;
 
        if (q == NULL)
                return -EINVAL;
@@ -416,10 +394,10 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked)
                return -EPERM;
        }
 
-       spin_lock_irqsave(&q->owner_lock, flags);
-       q->locked = locked ? 1 : 0;
-       q->owner = client;
-       spin_unlock_irqrestore(&q->owner_lock, flags);
+       scoped_guard(spinlock_irqsave, &q->owner_lock) {
+               q->locked = locked ? 1 : 0;
+               q->owner = client;
+       }
        queue_access_unlock(q);
        queuefree(q);
 
@@ -750,10 +728,10 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
                else
                        bpm = 0;
 
-               spin_lock_irq(&q->owner_lock);
-               locked = q->locked;
-               owner = q->owner;
-               spin_unlock_irq(&q->owner_lock);
+               scoped_guard(spinlock_irq, &q->owner_lock) {
+                       locked = q->locked;
+                       owner = q->owner;
+               }
 
                snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name);
                snd_iprintf(buffer, "owned by client    : %d\n", owner);
index 9863be6fd43e1a34aece5ffe258ffc627eb05bc2..ad2b97e2762d998c140eabf2a783340c8ed02e5a 100644 (file)
@@ -75,9 +75,7 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
 
 void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&tmr->lock, flags);
+       guard(spinlock_irqsave)(&tmr->lock);
        /* setup defaults */
        tmr->ppq = 96;          /* 96 PPQ */
        tmr->tempo = 500000;    /* 120 BPM */
@@ -93,7 +91,6 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
        tmr->preferred_resolution = seq_default_timer_resolution;
 
        tmr->skew = tmr->skew_base = SKEW_BASE;
-       spin_unlock_irqrestore(&tmr->lock, flags);
 }
 
 static void seq_timer_reset(struct snd_seq_timer *tmr)
@@ -108,11 +105,8 @@ static void seq_timer_reset(struct snd_seq_timer *tmr)
 
 void snd_seq_timer_reset(struct snd_seq_timer *tmr)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&tmr->lock, flags);
+       guard(spinlock_irqsave)(&tmr->lock);
        seq_timer_reset(tmr);
-       spin_unlock_irqrestore(&tmr->lock, flags);
 }
 
 
@@ -121,7 +115,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
                                    unsigned long resolution,
                                    unsigned long ticks)
 {
-       unsigned long flags;
        struct snd_seq_queue *q = timeri->callback_data;
        struct snd_seq_timer *tmr;
 
@@ -130,29 +123,27 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
        tmr = q->timer;
        if (tmr == NULL)
                return;
-       spin_lock_irqsave(&tmr->lock, flags);
-       if (!tmr->running) {
-               spin_unlock_irqrestore(&tmr->lock, flags);
-               return;
-       }
 
-       resolution *= ticks;
-       if (tmr->skew != tmr->skew_base) {
-               /* FIXME: assuming skew_base = 0x10000 */
-               resolution = (resolution >> 16) * tmr->skew +
-                       (((resolution & 0xffff) * tmr->skew) >> 16);
-       }
+       scoped_guard(spinlock_irqsave, &tmr->lock) {
+               if (!tmr->running)
+                       return;
 
-       /* update timer */
-       snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
+               resolution *= ticks;
+               if (tmr->skew != tmr->skew_base) {
+                       /* FIXME: assuming skew_base = 0x10000 */
+                       resolution = (resolution >> 16) * tmr->skew +
+                               (((resolution & 0xffff) * tmr->skew) >> 16);
+               }
 
-       /* calculate current tick */
-       snd_seq_timer_update_tick(&tmr->tick, resolution);
+               /* update timer */
+               snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
 
-       /* register actual time of this timer update */
-       ktime_get_ts64(&tmr->last_update);
+               /* calculate current tick */
+               snd_seq_timer_update_tick(&tmr->tick, resolution);
 
-       spin_unlock_irqrestore(&tmr->lock, flags);
+               /* register actual time of this timer update */
+               ktime_get_ts64(&tmr->last_update);
+       }
 
        /* check queues and dispatch events */
        snd_seq_check_queue(q, 1, 0);
@@ -161,18 +152,15 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
 /* set current tempo */
 int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
 {
-       unsigned long flags;
-
        if (snd_BUG_ON(!tmr))
                return -EINVAL;
        if (tempo <= 0)
                return -EINVAL;
-       spin_lock_irqsave(&tmr->lock, flags);
+       guard(spinlock_irqsave)(&tmr->lock);
        if ((unsigned int)tempo != tmr->tempo) {
                tmr->tempo = tempo;
                snd_seq_timer_set_tick_resolution(tmr);
        }
-       spin_unlock_irqrestore(&tmr->lock, flags);
        return 0;
 }
 
@@ -180,17 +168,15 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
 int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
 {
        int changed;
-       unsigned long flags;
 
        if (snd_BUG_ON(!tmr))
                return -EINVAL;
        if (tempo <= 0 || ppq <= 0)
                return -EINVAL;
-       spin_lock_irqsave(&tmr->lock, flags);
+       guard(spinlock_irqsave)(&tmr->lock);
        if (tmr->running && (ppq != tmr->ppq)) {
                /* refuse to change ppq on running timers */
                /* because it will upset the song position (ticks) */
-               spin_unlock_irqrestore(&tmr->lock, flags);
                pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
                return -EBUSY;
        }
@@ -199,7 +185,6 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
        tmr->ppq = ppq;
        if (changed)
                snd_seq_timer_set_tick_resolution(tmr);
-       spin_unlock_irqrestore(&tmr->lock, flags);
        return 0;
 }
 
@@ -207,15 +192,12 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
 int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
                                    snd_seq_tick_time_t position)
 {
-       unsigned long flags;
-
        if (snd_BUG_ON(!tmr))
                return -EINVAL;
 
-       spin_lock_irqsave(&tmr->lock, flags);
+       guard(spinlock_irqsave)(&tmr->lock);
        tmr->tick.cur_tick = position;
        tmr->tick.fraction = 0;
-       spin_unlock_irqrestore(&tmr->lock, flags);
        return 0;
 }
 
@@ -223,15 +205,12 @@ int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
 int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
                                    snd_seq_real_time_t position)
 {
-       unsigned long flags;
-
        if (snd_BUG_ON(!tmr))
                return -EINVAL;
 
        snd_seq_sanity_real_time(&position);
-       spin_lock_irqsave(&tmr->lock, flags);
+       guard(spinlock_irqsave)(&tmr->lock);
        tmr->cur_time = position;
-       spin_unlock_irqrestore(&tmr->lock, flags);
        return 0;
 }
 
@@ -239,8 +218,6 @@ int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
 int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
                           unsigned int base)
 {
-       unsigned long flags;
-
        if (snd_BUG_ON(!tmr))
                return -EINVAL;
 
@@ -249,9 +226,8 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
                pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
                return -EINVAL;
        }
-       spin_lock_irqsave(&tmr->lock, flags);
+       guard(spinlock_irqsave)(&tmr->lock);
        tmr->skew = skew;
-       spin_unlock_irqrestore(&tmr->lock, flags);
        return 0;
 }
 
@@ -296,12 +272,12 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
                snd_timer_instance_free(t);
                return err;
        }
-       spin_lock_irq(&tmr->lock);
-       if (tmr->timeri)
-               err = -EBUSY;
-       else
-               tmr->timeri = t;
-       spin_unlock_irq(&tmr->lock);
+       scoped_guard(spinlock_irq, &tmr->lock) {
+               if (tmr->timeri)
+                       err = -EBUSY;
+               else
+                       tmr->timeri = t;
+       }
        if (err < 0) {
                snd_timer_close(t);
                snd_timer_instance_free(t);
@@ -318,10 +294,10 @@ int snd_seq_timer_close(struct snd_seq_queue *q)
        tmr = q->timer;
        if (snd_BUG_ON(!tmr))
                return -EINVAL;
-       spin_lock_irq(&tmr->lock);
-       t = tmr->timeri;
-       tmr->timeri = NULL;
-       spin_unlock_irq(&tmr->lock);
+       scoped_guard(spinlock_irq, &tmr->lock) {
+               t = tmr->timeri;
+               tmr->timeri = NULL;
+       }
        if (t) {
                snd_timer_close(t);
                snd_timer_instance_free(t);
@@ -342,13 +318,8 @@ static int seq_timer_stop(struct snd_seq_timer *tmr)
 
 int snd_seq_timer_stop(struct snd_seq_timer *tmr)
 {
-       unsigned long flags;
-       int err;
-
-       spin_lock_irqsave(&tmr->lock, flags);
-       err = seq_timer_stop(tmr);
-       spin_unlock_irqrestore(&tmr->lock, flags);
-       return err;
+       guard(spinlock_irqsave)(&tmr->lock);
+       return seq_timer_stop(tmr);
 }
 
 static int initialize_timer(struct snd_seq_timer *tmr)
@@ -398,13 +369,8 @@ static int seq_timer_start(struct snd_seq_timer *tmr)
 
 int snd_seq_timer_start(struct snd_seq_timer *tmr)
 {
-       unsigned long flags;
-       int err;
-
-       spin_lock_irqsave(&tmr->lock, flags);
-       err = seq_timer_start(tmr);
-       spin_unlock_irqrestore(&tmr->lock, flags);
-       return err;
+       guard(spinlock_irqsave)(&tmr->lock);
+       return seq_timer_start(tmr);
 }
 
 static int seq_timer_continue(struct snd_seq_timer *tmr)
@@ -426,13 +392,8 @@ static int seq_timer_continue(struct snd_seq_timer *tmr)
 
 int snd_seq_timer_continue(struct snd_seq_timer *tmr)
 {
-       unsigned long flags;
-       int err;
-
-       spin_lock_irqsave(&tmr->lock, flags);
-       err = seq_timer_continue(tmr);
-       spin_unlock_irqrestore(&tmr->lock, flags);
-       return err;
+       guard(spinlock_irqsave)(&tmr->lock);
+       return seq_timer_continue(tmr);
 }
 
 /* return current 'real' time. use timeofday() to get better granularity. */
@@ -440,9 +401,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
                                               bool adjust_ktime)
 {
        snd_seq_real_time_t cur_time;
-       unsigned long flags;
 
-       spin_lock_irqsave(&tmr->lock, flags);
+       guard(spinlock_irqsave)(&tmr->lock);
        cur_time = tmr->cur_time;
        if (adjust_ktime && tmr->running) {
                struct timespec64 tm;
@@ -453,7 +413,6 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
                cur_time.tv_sec += tm.tv_sec;
                snd_seq_sanity_real_time(&cur_time);
        }
-       spin_unlock_irqrestore(&tmr->lock, flags);
        return cur_time;        
 }
 
@@ -461,13 +420,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
  high PPQ values) */
 snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
 {
-       snd_seq_tick_time_t cur_tick;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tmr->lock, flags);
-       cur_tick = tmr->tick.cur_tick;
-       spin_unlock_irqrestore(&tmr->lock, flags);
-       return cur_tick;
+       guard(spinlock_irqsave)(&tmr->lock);
+       return tmr->tick.cur_tick;
 }
 
 
@@ -486,19 +440,18 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry,
                q = queueptr(idx);
                if (q == NULL)
                        continue;
-               mutex_lock(&q->timer_mutex);
-               tmr = q->timer;
-               if (!tmr)
-                       goto unlock;
-               ti = tmr->timeri;
-               if (!ti)
-                       goto unlock;
-               snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
-               resolution = snd_timer_resolution(ti) * tmr->ticks;
-               snd_iprintf(buffer, "  Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
-               snd_iprintf(buffer, "  Skew : %u / %u\n", tmr->skew, tmr->skew_base);
-unlock:
-               mutex_unlock(&q->timer_mutex);
+               scoped_guard(mutex, &q->timer_mutex) {
+                       tmr = q->timer;
+                       if (!tmr)
+                               break;
+                       ti = tmr->timeri;
+                       if (!ti)
+                               break;
+                       snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
+                       resolution = snd_timer_resolution(ti) * tmr->ticks;
+                       snd_iprintf(buffer, "  Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
+                       snd_iprintf(buffer, "  Skew : %u / %u\n", tmr->skew, tmr->skew_base);
+               }
                queuefree(q);
        }
 }
index 2db371d79930d0f2af7630f50901a3d69006e538..c627d72f7fe2029579a9bc41cfea5fdcbe02ee70 100644 (file)
@@ -115,21 +115,19 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
 static int seq_ump_client_open(struct seq_ump_client *client, int dir)
 {
        struct snd_ump_endpoint *ump = client->ump;
-       int err = 0;
+       int err;
 
-       mutex_lock(&ump->open_mutex);
+       guard(mutex)(&ump->open_mutex);
        if (dir == STR_OUT && !client->opened[dir]) {
                err = snd_rawmidi_kernel_open(&ump->core, 0,
                                              SNDRV_RAWMIDI_LFLG_OUTPUT |
                                              SNDRV_RAWMIDI_LFLG_APPEND,
                                              &client->out_rfile);
                if (err < 0)
-                       goto unlock;
+                       return err;
        }
        client->opened[dir]++;
- unlock:
-       mutex_unlock(&ump->open_mutex);
-       return err;
+       return 0;
 }
 
 /* close the rawmidi */
@@ -137,11 +135,10 @@ static int seq_ump_client_close(struct seq_ump_client *client, int dir)
 {
        struct snd_ump_endpoint *ump = client->ump;
 
-       mutex_lock(&ump->open_mutex);
+       guard(mutex)(&ump->open_mutex);
        if (!--client->opened[dir])
                if (dir == STR_OUT)
                        snd_rawmidi_kernel_release(&client->out_rfile);
-       mutex_unlock(&ump->open_mutex);
        return 0;
 }
 
@@ -217,15 +214,12 @@ static void fill_port_info(struct snd_seq_port_info *port,
 static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
 {
        struct seq_ump_group *group = &client->groups[group_index];
-       struct snd_seq_port_info *port;
+       struct snd_seq_port_info *port __free(kfree) = NULL;
        struct snd_seq_port_callback pcallbacks;
-       int err;
 
        port = kzalloc(sizeof(*port), GFP_KERNEL);
-       if (!port) {
-               err = -ENOMEM;
-               goto error;
-       }
+       if (!port)
+               return -ENOMEM;
 
        fill_port_info(port, client, group);
        port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
@@ -238,24 +232,22 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
        pcallbacks.unuse = seq_ump_unuse;
        pcallbacks.event_input = seq_ump_process_event;
        port->kernel = &pcallbacks;
-       err = snd_seq_kernel_client_ctl(client->seq_client,
-                                       SNDRV_SEQ_IOCTL_CREATE_PORT,
-                                       port);
- error:
-       kfree(port);
-       return err;
+       return snd_seq_kernel_client_ctl(client->seq_client,
+                                        SNDRV_SEQ_IOCTL_CREATE_PORT,
+                                        port);
 }
 
 /* update the sequencer ports; called from notify_fb_change callback */
 static void update_port_infos(struct seq_ump_client *client)
 {
-       struct snd_seq_port_info *old, *new;
+       struct snd_seq_port_info *old __free(kfree) = NULL;
+       struct snd_seq_port_info *new __free(kfree) = NULL;
        int i, err;
 
        old = kzalloc(sizeof(*old), GFP_KERNEL);
        new = kzalloc(sizeof(*new), GFP_KERNEL);
        if (!old || !new)
-               goto error;
+               return;
 
        for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
                old->addr.client = client->seq_client;
@@ -264,7 +256,7 @@ static void update_port_infos(struct seq_ump_client *client)
                                                SNDRV_SEQ_IOCTL_GET_PORT_INFO,
                                                old);
                if (err < 0)
-                       goto error;
+                       return;
                fill_port_info(new, client, &client->groups[i]);
                if (old->capability == new->capability &&
                    !strcmp(old->name, new->name))
@@ -273,13 +265,10 @@ static void update_port_infos(struct seq_ump_client *client)
                                                SNDRV_SEQ_IOCTL_SET_PORT_INFO,
                                                new);
                if (err < 0)
-                       goto error;
+                       return;
                /* notify to system port */
                snd_seq_system_client_ev_port_change(client->seq_client, i);
        }
- error:
-       kfree(new);
-       kfree(old);
 }
 
 /* update dir_bits and active flag for all groups in the client */
@@ -334,7 +323,7 @@ static void update_group_attrs(struct seq_ump_client *client)
 /* create a UMP Endpoint port */
 static int create_ump_endpoint_port(struct seq_ump_client *client)
 {
-       struct snd_seq_port_info *port;
+       struct snd_seq_port_info *port __free(kfree) = NULL;
        struct snd_seq_port_callback pcallbacks;
        unsigned int rawmidi_info = client->ump->core.info_flags;
        int err;
@@ -383,7 +372,6 @@ static int create_ump_endpoint_port(struct seq_ump_client *client)
        err = snd_seq_kernel_client_ctl(client->seq_client,
                                        SNDRV_SEQ_IOCTL_CREATE_PORT,
                                        port);
-       kfree(port);
        return err;
 }
 
index 1b9260108e48219b35fc66b04149db647c2a6775..b4672613c26136adf778cde4a72e7274abcddd18 100644 (file)
@@ -62,6 +62,13 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
 /*
  * decode input event and put to read buffer of each opened file
  */
+
+/* callback for snd_seq_dump_var_event(), bridging to snd_rawmidi_receive() */
+static int dump_to_rawmidi(void *ptr, void *buf, int count)
+{
+       return snd_rawmidi_receive(ptr, buf, count);
+}
+
 static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
                                         struct snd_seq_event *ev,
                                         bool atomic)
@@ -80,7 +87,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
                if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
                        if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
                                continue;
-                       snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream);
+                       snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream);
                        snd_midi_event_reset_decode(vmidi->parser);
                } else {
                        len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
@@ -192,11 +199,10 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
        vmidi->client = rdev->client;
        vmidi->port = rdev->port;       
        runtime->private_data = vmidi;
-       down_write(&rdev->filelist_sem);
-       write_lock_irq(&rdev->filelist_lock);
-       list_add_tail(&vmidi->list, &rdev->filelist);
-       write_unlock_irq(&rdev->filelist_lock);
-       up_write(&rdev->filelist_sem);
+       scoped_guard(rwsem_write, &rdev->filelist_sem) {
+               guard(write_lock_irq)(&rdev->filelist_lock);
+               list_add_tail(&vmidi->list, &rdev->filelist);
+       }
        vmidi->rdev = rdev;
        return 0;
 }
@@ -236,11 +242,10 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
        struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
        struct snd_virmidi *vmidi = substream->runtime->private_data;
 
-       down_write(&rdev->filelist_sem);
-       write_lock_irq(&rdev->filelist_lock);
-       list_del(&vmidi->list);
-       write_unlock_irq(&rdev->filelist_lock);
-       up_write(&rdev->filelist_sem);
+       scoped_guard(rwsem_write, &rdev->filelist_sem) {
+               guard(write_lock_irq)(&rdev->filelist_lock);
+               list_del(&vmidi->list);
+       }
        snd_midi_event_free(vmidi->parser);
        substream->runtime->private_data = NULL;
        kfree(vmidi);
@@ -356,26 +361,22 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
 {
        int client;
        struct snd_seq_port_callback pcallbacks;
-       struct snd_seq_port_info *pinfo;
+       struct snd_seq_port_info *pinfo __free(kfree) = NULL;
        int err;
 
        if (rdev->client >= 0)
                return 0;
 
        pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
-       if (!pinfo) {
-               err = -ENOMEM;
-               goto __error;
-       }
+       if (!pinfo)
+               return -ENOMEM;
 
        client = snd_seq_create_kernel_client(rdev->card, rdev->device,
                                              "%s %d-%d", rdev->rmidi->name,
                                              rdev->card->number,
                                              rdev->device);
-       if (client < 0) {
-               err = client;
-               goto __error;
-       }
+       if (client < 0)
+               return client;
        rdev->client = client;
 
        /* create a port */
@@ -403,15 +404,11 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
        if (err < 0) {
                snd_seq_delete_kernel_client(client);
                rdev->client = -1;
-               goto __error;
+               return err;
        }
 
        rdev->port = pinfo->addr.port;
-       err = 0; /* success */
-
- __error:
-       kfree(pinfo);
-       return err;
+       return 0; /* success */
 }
 
 
index 7f3fd8eb016fe825e13394576f803f0f27603fe0..654d620d0199f7e0e501075d22899ff37afa937a 100644 (file)
@@ -49,7 +49,7 @@ static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
                sdrv->argsize == sdev->argsize;
 }
 
-static struct bus_type snd_seq_bus_type = {
+static const struct bus_type snd_seq_bus_type = {
        .name = "snd_seq",
        .match = snd_seq_bus_match,
 };
index df5571d9862955fe576be3be5649d67a61e170c3..b9db9aa0bfcb583a143a88347ab7d4cdf37321fa 100644 (file)
@@ -103,7 +103,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
 
        if (minor >= ARRAY_SIZE(snd_minors))
                return NULL;
-       mutex_lock(&sound_mutex);
+       guard(mutex)(&sound_mutex);
        mreg = snd_minors[minor];
        if (mreg && mreg->type == type) {
                private_data = mreg->private_data;
@@ -111,7 +111,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
                        get_device(&mreg->card_ptr->card_dev);
        } else
                private_data = NULL;
-       mutex_unlock(&sound_mutex);
        return private_data;
 }
 EXPORT_SYMBOL(snd_lookup_minor_data);
@@ -150,17 +149,15 @@ static int snd_open(struct inode *inode, struct file *file)
 
        if (minor >= ARRAY_SIZE(snd_minors))
                return -ENODEV;
-       mutex_lock(&sound_mutex);
-       mptr = snd_minors[minor];
-       if (mptr == NULL) {
-               mptr = autoload_device(minor);
-               if (!mptr) {
-                       mutex_unlock(&sound_mutex);
-                       return -ENODEV;
+       scoped_guard(mutex, &sound_mutex) {
+               mptr = snd_minors[minor];
+               if (mptr == NULL) {
+                       mptr = autoload_device(minor);
+                       if (!mptr)
+                               return -ENODEV;
                }
+               new_fops = fops_get(mptr->f_ops);
        }
-       new_fops = fops_get(mptr->f_ops);
-       mutex_unlock(&sound_mutex);
        if (!new_fops)
                return -ENODEV;
        replace_fops(file, new_fops);
@@ -269,7 +266,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
        preg->f_ops = f_ops;
        preg->private_data = private_data;
        preg->card_ptr = card;
-       mutex_lock(&sound_mutex);
+       guard(mutex)(&sound_mutex);
        minor = snd_find_free_minor(type, card, dev);
        if (minor < 0) {
                err = minor;
@@ -284,7 +281,6 @@ int snd_register_device(int type, struct snd_card *card, int dev,
 
        snd_minors[minor] = preg;
  error:
-       mutex_unlock(&sound_mutex);
        if (err < 0)
                kfree(preg);
        return err;
@@ -305,7 +301,7 @@ int snd_unregister_device(struct device *dev)
        int minor;
        struct snd_minor *preg;
 
-       mutex_lock(&sound_mutex);
+       guard(mutex)(&sound_mutex);
        for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
                preg = snd_minors[minor];
                if (preg && preg->dev == dev) {
@@ -315,7 +311,6 @@ int snd_unregister_device(struct device *dev)
                        break;
                }
        }
-       mutex_unlock(&sound_mutex);
        if (minor >= ARRAY_SIZE(snd_minors))
                return -ENOENT;
        return 0;
@@ -355,7 +350,7 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
        int minor;
        struct snd_minor *mptr;
 
-       mutex_lock(&sound_mutex);
+       guard(mutex)(&sound_mutex);
        for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
                mptr = snd_minors[minor];
                if (!mptr)
@@ -373,7 +368,6 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
                        snd_iprintf(buffer, "%3i:        : %s\n", minor,
                                    snd_device_type_name(mptr->type));
        }
-       mutex_unlock(&sound_mutex);
 }
 
 int __init snd_minor_info_init(void)
diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c
new file mode 100644 (file)
index 0000000..eb90f62
--- /dev/null
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Sound core KUnit test
+ * Author: Ivan Orlov <ivan.orlov0322@gmail.com>
+ */
+
+#include <kunit/test.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#define SILENCE_BUFFER_MAX_FRAMES 260
+#define SILENCE_BUFFER_SIZE (sizeof(u64) * SILENCE_BUFFER_MAX_FRAMES)
+#define SILENCE(...) { __VA_ARGS__ }
+#define DEFINE_FORMAT(fmt, pbits, wd, endianness, signd, silence_arr) {                \
+       .format = SNDRV_PCM_FORMAT_##fmt, .physical_bits = pbits,               \
+       .width = wd, .le = endianness, .sd = signd, .silence = silence_arr,     \
+       .name = #fmt,                                                           \
+}
+
+#define WRONG_FORMAT_1 (__force snd_pcm_format_t)((__force int)SNDRV_PCM_FORMAT_LAST + 1)
+#define WRONG_FORMAT_2 (__force snd_pcm_format_t)-1
+
+#define VALID_NAME "ValidName"
+#define NAME_W_SPEC_CHARS "In%v@1id name"
+#define NAME_W_SPACE "Test name"
+#define NAME_W_SPACE_REMOVED "Testname"
+
+#define TEST_FIRST_COMPONENT "Component1"
+#define TEST_SECOND_COMPONENT "Component2"
+
+struct snd_format_test_data {
+       snd_pcm_format_t format;
+       int physical_bits;
+       int width;
+       int le;
+       int sd;
+       unsigned char silence[8];
+       unsigned char *name;
+};
+
+struct avail_test_data {
+       snd_pcm_uframes_t buffer_size;
+       snd_pcm_uframes_t hw_ptr;
+       snd_pcm_uframes_t appl_ptr;
+       snd_pcm_uframes_t expected_avail;
+};
+
+static struct snd_format_test_data valid_fmt[] = {
+       DEFINE_FORMAT(S8, 8, 8, -1, 1, SILENCE()),
+       DEFINE_FORMAT(U8, 8, 8, -1, 0, SILENCE(0x80)),
+       DEFINE_FORMAT(S16_LE, 16, 16, 1, 1, SILENCE()),
+       DEFINE_FORMAT(S16_BE, 16, 16, 0, 1, SILENCE()),
+       DEFINE_FORMAT(U16_LE, 16, 16, 1, 0, SILENCE(0x00, 0x80)),
+       DEFINE_FORMAT(U16_BE, 16, 16, 0, 0, SILENCE(0x80, 0x00)),
+       DEFINE_FORMAT(S24_LE, 32, 24, 1, 1, SILENCE()),
+       DEFINE_FORMAT(S24_BE, 32, 24, 0, 1, SILENCE()),
+       DEFINE_FORMAT(U24_LE, 32, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
+       DEFINE_FORMAT(U24_BE, 32, 24, 0, 0, SILENCE(0x00, 0x80, 0x00, 0x00)),
+       DEFINE_FORMAT(S32_LE, 32, 32, 1, 1, SILENCE()),
+       DEFINE_FORMAT(S32_BE, 32, 32, 0, 1, SILENCE()),
+       DEFINE_FORMAT(U32_LE, 32, 32, 1, 0, SILENCE(0x00, 0x00, 0x00, 0x80)),
+       DEFINE_FORMAT(U32_BE, 32, 32, 0, 0, SILENCE(0x80, 0x00, 0x00, 0x00)),
+       DEFINE_FORMAT(FLOAT_LE, 32, 32, 1, -1, SILENCE()),
+       DEFINE_FORMAT(FLOAT_BE, 32, 32, 0, -1, SILENCE()),
+       DEFINE_FORMAT(FLOAT64_LE, 64, 64, 1, -1, SILENCE()),
+       DEFINE_FORMAT(FLOAT64_BE, 64, 64, 0, -1, SILENCE()),
+       DEFINE_FORMAT(IEC958_SUBFRAME_LE, 32, 32, 1, -1, SILENCE()),
+       DEFINE_FORMAT(IEC958_SUBFRAME_BE, 32, 32, 0, -1, SILENCE()),
+       DEFINE_FORMAT(MU_LAW, 8, 8, -1, -1, SILENCE(0x7f)),
+       DEFINE_FORMAT(A_LAW, 8, 8, -1, -1, SILENCE(0x55)),
+       DEFINE_FORMAT(IMA_ADPCM, 4, 4, -1, -1, SILENCE()),
+       DEFINE_FORMAT(G723_24, 3, 3, -1, -1, SILENCE()),
+       DEFINE_FORMAT(G723_40, 5, 5, -1, -1, SILENCE()),
+       DEFINE_FORMAT(DSD_U8, 8, 8, 1, 0, SILENCE(0x69)),
+       DEFINE_FORMAT(DSD_U16_LE, 16, 16, 1, 0, SILENCE(0x69, 0x69)),
+       DEFINE_FORMAT(DSD_U32_LE, 32, 32, 1, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
+       DEFINE_FORMAT(DSD_U16_BE, 16, 16, 0, 0, SILENCE(0x69, 0x69)),
+       DEFINE_FORMAT(DSD_U32_BE, 32, 32, 0, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
+       DEFINE_FORMAT(S20_LE, 32, 20, 1, 1, SILENCE()),
+       DEFINE_FORMAT(S20_BE, 32, 20, 0, 1, SILENCE()),
+       DEFINE_FORMAT(U20_LE, 32, 20, 1, 0, SILENCE(0x00, 0x00, 0x08, 0x00)),
+       DEFINE_FORMAT(U20_BE, 32, 20, 0, 0, SILENCE(0x00, 0x08, 0x00, 0x00)),
+       DEFINE_FORMAT(S24_3LE, 24, 24, 1, 1, SILENCE()),
+       DEFINE_FORMAT(S24_3BE, 24, 24, 0, 1, SILENCE()),
+       DEFINE_FORMAT(U24_3LE, 24, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
+       DEFINE_FORMAT(U24_3BE, 24, 24, 0, 0, SILENCE(0x80, 0x00, 0x00)),
+       DEFINE_FORMAT(S20_3LE, 24, 20, 1, 1, SILENCE()),
+       DEFINE_FORMAT(S20_3BE, 24, 20, 0, 1, SILENCE()),
+       DEFINE_FORMAT(U20_3LE, 24, 20, 1, 0, SILENCE(0x00, 0x00, 0x08)),
+       DEFINE_FORMAT(U20_3BE, 24, 20, 0, 0, SILENCE(0x08, 0x00, 0x00)),
+       DEFINE_FORMAT(S18_3LE, 24, 18, 1, 1, SILENCE()),
+       DEFINE_FORMAT(S18_3BE, 24, 18, 0, 1, SILENCE()),
+       DEFINE_FORMAT(U18_3LE, 24, 18, 1, 0, SILENCE(0x00, 0x00, 0x02)),
+       DEFINE_FORMAT(U18_3BE, 24, 18, 0, 0, SILENCE(0x02, 0x00, 0x00)),
+       DEFINE_FORMAT(G723_24_1B, 8, 3, -1, -1, SILENCE()),
+       DEFINE_FORMAT(G723_40_1B, 8, 5, -1, -1, SILENCE()),
+};
+
+static void test_phys_format_size(struct kunit *test)
+{
+       u32 i;
+
+       for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+               KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(valid_fmt[i].format),
+                               valid_fmt[i].physical_bits);
+       }
+
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_1), -EINVAL);
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_2), -EINVAL);
+}
+
+static void test_format_width(struct kunit *test)
+{
+       u32 i;
+
+       for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+               KUNIT_EXPECT_EQ(test, snd_pcm_format_width(valid_fmt[i].format),
+                               valid_fmt[i].width);
+       }
+
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL);
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL);
+}
+
+static void test_format_signed(struct kunit *test)
+{
+       u32 i;
+
+       for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+               KUNIT_EXPECT_EQ(test, snd_pcm_format_signed(valid_fmt[i].format),
+                               valid_fmt[i].sd < 0 ? -EINVAL : valid_fmt[i].sd);
+               KUNIT_EXPECT_EQ(test, snd_pcm_format_unsigned(valid_fmt[i].format),
+                               valid_fmt[i].sd < 0 ? -EINVAL : 1 - valid_fmt[i].sd);
+       }
+
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL);
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL);
+}
+
+static void test_format_endianness(struct kunit *test)
+{
+       u32 i;
+
+       for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+               KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(valid_fmt[i].format),
+                               valid_fmt[i].le < 0 ? -EINVAL : valid_fmt[i].le);
+               KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(valid_fmt[i].format),
+                               valid_fmt[i].le < 0 ? -EINVAL : 1 - valid_fmt[i].le);
+       }
+
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_1), -EINVAL);
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_2), -EINVAL);
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_1), -EINVAL);
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_2), -EINVAL);
+}
+
+static void _test_fill_silence(struct kunit *test, struct snd_format_test_data *data,
+                              u8 *buffer, size_t samples_count)
+{
+       size_t sample_bytes = data->physical_bits >> 3;
+       u32 i;
+
+       KUNIT_ASSERT_EQ(test, snd_pcm_format_set_silence(data->format, buffer, samples_count), 0);
+       for (i = 0; i < samples_count * sample_bytes; i++)
+               KUNIT_EXPECT_EQ(test, buffer[i], data->silence[i % sample_bytes]);
+}
+
+static void test_format_fill_silence(struct kunit *test)
+{
+       u32 buf_samples[] = { 10, 20, 32, 64, 129, SILENCE_BUFFER_MAX_FRAMES };
+       u8 *buffer;
+       u32 i, j;
+
+       buffer = kunit_kzalloc(test, SILENCE_BUFFER_SIZE, GFP_KERNEL);
+
+       for (i = 0; i < ARRAY_SIZE(buf_samples); i++) {
+               for (j = 0; j < ARRAY_SIZE(valid_fmt); j++)
+                       _test_fill_silence(test, &valid_fmt[j], buffer, buf_samples[i]);
+       }
+
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(WRONG_FORMAT_1, buffer, 20), -EINVAL);
+       KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(SNDRV_PCM_FORMAT_LAST, buffer, 0), 0);
+}
+
+static snd_pcm_uframes_t calculate_boundary(snd_pcm_uframes_t buffer_size)
+{
+       snd_pcm_uframes_t boundary = buffer_size;
+
+       while (boundary * 2 <= 0x7fffffffUL - buffer_size)
+               boundary *= 2;
+       return boundary;
+}
+
+static struct avail_test_data p_avail_data[] = {
+       /* buf_size + hw_ptr < appl_ptr => avail = buf_size + hw_ptr - appl_ptr + boundary */
+       { 128, 1000, 1129, 1073741824UL - 1 },
+       /*
+        * buf_size + hw_ptr - appl_ptr >= boundary =>
+        * => avail = buf_size + hw_ptr - appl_ptr - boundary
+        */
+       { 128, 1073741824UL, 10, 118 },
+       /* standard case: avail = buf_size + hw_ptr - appl_ptr */
+       { 128, 1000, 1001, 127 },
+};
+
+static void test_playback_avail(struct kunit *test)
+{
+       struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
+       u32 i;
+
+       r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
+       r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
+
+       for (i = 0; i < ARRAY_SIZE(p_avail_data); i++) {
+               r->buffer_size = p_avail_data[i].buffer_size;
+               r->boundary = calculate_boundary(r->buffer_size);
+               r->status->hw_ptr = p_avail_data[i].hw_ptr;
+               r->control->appl_ptr = p_avail_data[i].appl_ptr;
+               KUNIT_EXPECT_EQ(test, snd_pcm_playback_avail(r), p_avail_data[i].expected_avail);
+       }
+}
+
+static struct avail_test_data c_avail_data[] = {
+       /* hw_ptr - appl_ptr < 0 => avail = hw_ptr - appl_ptr + boundary */
+       { 128, 1000, 1001, 1073741824UL - 1 },
+       /* standard case: avail = hw_ptr - appl_ptr */
+       { 128, 1001, 1000, 1 },
+};
+
+static void test_capture_avail(struct kunit *test)
+{
+       struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
+       u32 i;
+
+       r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
+       r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
+
+       for (i = 0; i < ARRAY_SIZE(c_avail_data); i++) {
+               r->buffer_size = c_avail_data[i].buffer_size;
+               r->boundary = calculate_boundary(r->buffer_size);
+               r->status->hw_ptr = c_avail_data[i].hw_ptr;
+               r->control->appl_ptr = c_avail_data[i].appl_ptr;
+               KUNIT_EXPECT_EQ(test, snd_pcm_capture_avail(r), c_avail_data[i].expected_avail);
+       }
+}
+
+static void test_card_set_id(struct kunit *test)
+{
+       struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
+
+       snd_card_set_id(card, VALID_NAME);
+       KUNIT_EXPECT_STREQ(test, card->id, VALID_NAME);
+
+       /* clear the first id character so we can set it again */
+       card->id[0] = '\0';
+       snd_card_set_id(card, NAME_W_SPEC_CHARS);
+       KUNIT_EXPECT_STRNEQ(test, card->id, NAME_W_SPEC_CHARS);
+
+       card->id[0] = '\0';
+       snd_card_set_id(card, NAME_W_SPACE);
+       kunit_info(test, "%s", card->id);
+       KUNIT_EXPECT_STREQ(test, card->id, NAME_W_SPACE_REMOVED);
+}
+
+static void test_pcm_format_name(struct kunit *test)
+{
+       u32 i;
+       const char *name;
+
+       for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+               name = snd_pcm_format_name(valid_fmt[i].format);
+               KUNIT_ASSERT_NOT_NULL_MSG(test, name, "Don't have name for %s", valid_fmt[i].name);
+               KUNIT_EXPECT_STREQ(test, name, valid_fmt[i].name);
+       }
+
+       KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_1), "Unknown");
+       KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_2), "Unknown");
+}
+
+static void test_card_add_component(struct kunit *test)
+{
+       struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
+
+       snd_component_add(card, TEST_FIRST_COMPONENT);
+       KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT);
+
+       snd_component_add(card, TEST_SECOND_COMPONENT);
+       KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT " " TEST_SECOND_COMPONENT);
+}
+
+static struct kunit_case sound_utils_cases[] = {
+       KUNIT_CASE(test_phys_format_size),
+       KUNIT_CASE(test_format_width),
+       KUNIT_CASE(test_format_endianness),
+       KUNIT_CASE(test_format_signed),
+       KUNIT_CASE(test_format_fill_silence),
+       KUNIT_CASE(test_playback_avail),
+       KUNIT_CASE(test_capture_avail),
+       KUNIT_CASE(test_card_set_id),
+       KUNIT_CASE(test_pcm_format_name),
+       KUNIT_CASE(test_card_add_component),
+       {},
+};
+
+static struct kunit_suite sound_utils_suite = {
+       .name = "sound-core-test",
+       .test_cases = sound_utils_cases,
+};
+
+kunit_test_suite(sound_utils_suite);
+MODULE_AUTHOR("Ivan Orlov");
+MODULE_LICENSE("GPL");
index 2751bf2ff61bca8dfd54125489c5ab047c45bb9b..d65cc6fee2e60ce6d10ba817e5e7fbcaf9e887e2 100644 (file)
@@ -29,7 +29,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
 
        if (minor >= ARRAY_SIZE(snd_oss_minors))
                return NULL;
-       mutex_lock(&sound_oss_mutex);
+       guard(mutex)(&sound_oss_mutex);
        mreg = snd_oss_minors[minor];
        if (mreg && mreg->type == type) {
                private_data = mreg->private_data;
@@ -37,7 +37,6 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
                        get_device(&mreg->card_ptr->card_dev);
        } else
                private_data = NULL;
-       mutex_unlock(&sound_oss_mutex);
        return private_data;
 }
 EXPORT_SYMBOL(snd_lookup_oss_minor_data);
@@ -106,7 +105,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
        preg->f_ops = f_ops;
        preg->private_data = private_data;
        preg->card_ptr = card;
-       mutex_lock(&sound_oss_mutex);
+       guard(mutex)(&sound_oss_mutex);
        snd_oss_minors[minor] = preg;
        minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
        switch (minor_unit) {
@@ -130,7 +129,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
                        goto __end;
                snd_oss_minors[track2] = preg;
        }
-       mutex_unlock(&sound_oss_mutex);
        return 0;
 
       __end:
@@ -139,7 +137,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
        if (register1 >= 0)
                unregister_sound_special(register1);
        snd_oss_minors[minor] = NULL;
-       mutex_unlock(&sound_oss_mutex);
        kfree(preg);
        return -EBUSY;
 }
@@ -156,12 +153,10 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
                return 0;
        if (minor < 0)
                return minor;
-       mutex_lock(&sound_oss_mutex);
+       guard(mutex)(&sound_oss_mutex);
        mptr = snd_oss_minors[minor];
-       if (mptr == NULL) {
-               mutex_unlock(&sound_oss_mutex);
+       if (mptr == NULL)
                return -ENOENT;
-       }
        switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
        case SNDRV_MINOR_OSS_PCM:
                track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
@@ -176,7 +171,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
        if (track2 >= 0)
                snd_oss_minors[track2] = NULL;
        snd_oss_minors[minor] = NULL;
-       mutex_unlock(&sound_oss_mutex);
 
        /* call unregister_sound_special() outside sound_oss_mutex;
         * otherwise may deadlock, as it can trigger the release of a card
@@ -220,7 +214,7 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
        int minor;
        struct snd_minor *mptr;
 
-       mutex_lock(&sound_oss_mutex);
+       guard(mutex)(&sound_oss_mutex);
        for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
                mptr = snd_oss_minors[minor];
                if (!mptr)
@@ -233,7 +227,6 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
                        snd_iprintf(buffer, "%3i:       : %s\n", minor,
                                    snd_oss_device_type_name(mptr->type));
        }
-       mutex_unlock(&sound_oss_mutex);
 }
 
 
index e6e551d4a29e0137a1a769576d6c1ccff3e041be..4d2ee99c12a3fb2a5af3dcebc4bc9a77efadcccb 100644 (file)
@@ -224,14 +224,12 @@ static int check_matching_master_slave(struct snd_timer_instance *master,
                return -EBUSY;
        list_move_tail(&slave->open_list, &master->slave_list_head);
        master->timer->num_instances++;
-       spin_lock_irq(&slave_active_lock);
-       spin_lock(&master->timer->lock);
+       guard(spinlock_irq)(&slave_active_lock);
+       guard(spinlock)(&master->timer->lock);
        slave->master = master;
        slave->timer = master->timer;
        if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
                list_add_tail(&slave->active_list, &master->slave_active_head);
-       spin_unlock(&master->timer->lock);
-       spin_unlock_irq(&slave_active_lock);
        return 1;
 }
 
@@ -382,6 +380,25 @@ list_added:
 }
 EXPORT_SYMBOL(snd_timer_open);
 
+/* remove slave links, called from snd_timer_close_locked() below */
+static void remove_slave_links(struct snd_timer_instance *timeri,
+                              struct snd_timer *timer)
+{
+       struct snd_timer_instance *slave, *tmp;
+
+       guard(spinlock_irq)(&slave_active_lock);
+       guard(spinlock)(&timer->lock);
+       timeri->timer = NULL;
+       list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) {
+               list_move_tail(&slave->open_list, &snd_timer_slave_list);
+               timer->num_instances--;
+               slave->master = NULL;
+               slave->timer = NULL;
+               list_del_init(&slave->ack_list);
+               list_del_init(&slave->active_list);
+       }
+}
+
 /*
  * close a timer instance
  * call this with register_mutex down.
@@ -390,12 +407,10 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
                                   struct device **card_devp_to_put)
 {
        struct snd_timer *timer = timeri->timer;
-       struct snd_timer_instance *slave, *tmp;
 
        if (timer) {
-               spin_lock_irq(&timer->lock);
+               guard(spinlock_irq)(&timer->lock);
                timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
-               spin_unlock_irq(&timer->lock);
        }
 
        if (!list_empty(&timeri->open_list)) {
@@ -418,21 +433,7 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
                }
                spin_unlock_irq(&timer->lock);
 
-               /* remove slave links */
-               spin_lock_irq(&slave_active_lock);
-               spin_lock(&timer->lock);
-               timeri->timer = NULL;
-               list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
-                                        open_list) {
-                       list_move_tail(&slave->open_list, &snd_timer_slave_list);
-                       timer->num_instances--;
-                       slave->master = NULL;
-                       slave->timer = NULL;
-                       list_del_init(&slave->ack_list);
-                       list_del_init(&slave->active_list);
-               }
-               spin_unlock(&timer->lock);
-               spin_unlock_irq(&slave_active_lock);
+               remove_slave_links(timeri, timer);
 
                /* slave doesn't need to release timer resources below */
                if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
@@ -459,9 +460,8 @@ void snd_timer_close(struct snd_timer_instance *timeri)
        if (snd_BUG_ON(!timeri))
                return;
 
-       mutex_lock(&register_mutex);
-       snd_timer_close_locked(timeri, &card_dev_to_put);
-       mutex_unlock(&register_mutex);
+       scoped_guard(mutex, &register_mutex)
+               snd_timer_close_locked(timeri, &card_dev_to_put);
        /* put_device() is called after unlock for avoiding deadlock */
        if (card_dev_to_put)
                put_device(card_dev_to_put);
@@ -480,15 +480,13 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
 {
        struct snd_timer * timer;
        unsigned long ret = 0;
-       unsigned long flags;
 
        if (timeri == NULL)
                return 0;
        timer = timeri->timer;
        if (timer) {
-               spin_lock_irqsave(&timer->lock, flags);
+               guard(spinlock_irqsave)(&timer->lock);
                ret = snd_timer_hw_resolution(timer);
-               spin_unlock_irqrestore(&timer->lock, flags);
        }
        return ret;
 }
@@ -532,26 +530,19 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
 {
        struct snd_timer *timer;
        int result;
-       unsigned long flags;
 
        timer = timeri->timer;
        if (!timer)
                return -EINVAL;
 
-       spin_lock_irqsave(&timer->lock, flags);
-       if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
-               result = -EINVAL;
-               goto unlock;
-       }
-       if (timer->card && timer->card->shutdown) {
-               result = -ENODEV;
-               goto unlock;
-       }
+       guard(spinlock_irqsave)(&timer->lock);
+       if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
+               return -EINVAL;
+       if (timer->card && timer->card->shutdown)
+               return -ENODEV;
        if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
-                            SNDRV_TIMER_IFLG_START)) {
-               result = -EBUSY;
-               goto unlock;
-       }
+                            SNDRV_TIMER_IFLG_START))
+               return -EBUSY;
 
        if (start)
                timeri->ticks = timeri->cticks = ticks;
@@ -577,8 +568,6 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
        }
        snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
                          SNDRV_TIMER_EVENT_CONTINUE);
- unlock:
-       spin_unlock_irqrestore(&timer->lock, flags);
        return result;
 }
 
@@ -586,53 +575,38 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
 static int snd_timer_start_slave(struct snd_timer_instance *timeri,
                                 bool start)
 {
-       unsigned long flags;
-       int err;
-
-       spin_lock_irqsave(&slave_active_lock, flags);
-       if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
-               err = -EINVAL;
-               goto unlock;
-       }
-       if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
-               err = -EBUSY;
-               goto unlock;
-       }
+       guard(spinlock_irqsave)(&slave_active_lock);
+       if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
+               return -EINVAL;
+       if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING)
+               return -EBUSY;
        timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
        if (timeri->master && timeri->timer) {
-               spin_lock(&timeri->timer->lock);
+               guard(spinlock)(&timeri->timer->lock);
                list_add_tail(&timeri->active_list,
                              &timeri->master->slave_active_head);
                snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
                                  SNDRV_TIMER_EVENT_CONTINUE);
-               spin_unlock(&timeri->timer->lock);
        }
-       err = 1; /* delayed start */
- unlock:
-       spin_unlock_irqrestore(&slave_active_lock, flags);
-       return err;
+       return 1; /* delayed start */
 }
 
 /* stop/pause a master timer */
 static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
 {
        struct snd_timer *timer;
-       int result = 0;
-       unsigned long flags;
 
        timer = timeri->timer;
        if (!timer)
                return -EINVAL;
-       spin_lock_irqsave(&timer->lock, flags);
+       guard(spinlock_irqsave)(&timer->lock);
        list_del_init(&timeri->ack_list);
        list_del_init(&timeri->active_list);
        if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
-                              SNDRV_TIMER_IFLG_START))) {
-               result = -EBUSY;
-               goto unlock;
-       }
+                              SNDRV_TIMER_IFLG_START)))
+               return -EBUSY;
        if (timer->card && timer->card->shutdown)
-               goto unlock;
+               return 0;
        if (stop) {
                timeri->cticks = timeri->ticks;
                timeri->pticks = 0;
@@ -656,30 +630,25 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
                timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
        snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
                          SNDRV_TIMER_EVENT_PAUSE);
- unlock:
-       spin_unlock_irqrestore(&timer->lock, flags);
-       return result;
+       return 0;
 }
 
 /* stop/pause a slave timer */
 static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
 {
-       unsigned long flags;
        bool running;
 
-       spin_lock_irqsave(&slave_active_lock, flags);
+       guard(spinlock_irqsave)(&slave_active_lock);
        running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING;
        timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
        if (timeri->timer) {
-               spin_lock(&timeri->timer->lock);
+               guard(spinlock)(&timeri->timer->lock);
                list_del_init(&timeri->ack_list);
                list_del_init(&timeri->active_list);
                if (running)
                        snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
                                          SNDRV_TIMER_EVENT_PAUSE);
-               spin_unlock(&timeri->timer->lock);
        }
-       spin_unlock_irqrestore(&slave_active_lock, flags);
        return running ? 0 : -EBUSY;
 }
 
@@ -804,12 +773,9 @@ static void snd_timer_process_callbacks(struct snd_timer *timer,
 static void snd_timer_clear_callbacks(struct snd_timer *timer,
                                      struct list_head *head)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&timer->lock, flags);
+       guard(spinlock_irqsave)(&timer->lock);
        while (!list_empty(head))
                list_del_init(head->next);
-       spin_unlock_irqrestore(&timer->lock, flags);
 }
 
 /*
@@ -819,16 +785,14 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer,
 static void snd_timer_work(struct work_struct *work)
 {
        struct snd_timer *timer = container_of(work, struct snd_timer, task_work);
-       unsigned long flags;
 
        if (timer->card && timer->card->shutdown) {
                snd_timer_clear_callbacks(timer, &timer->sack_list_head);
                return;
        }
 
-       spin_lock_irqsave(&timer->lock, flags);
+       guard(spinlock_irqsave)(&timer->lock);
        snd_timer_process_callbacks(timer, &timer->sack_list_head);
-       spin_unlock_irqrestore(&timer->lock, flags);
 }
 
 /*
@@ -842,8 +806,6 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
        struct snd_timer_instance *ti, *ts, *tmp;
        unsigned long resolution;
        struct list_head *ack_list_head;
-       unsigned long flags;
-       bool use_work = false;
 
        if (timer == NULL)
                return;
@@ -853,7 +815,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
                return;
        }
 
-       spin_lock_irqsave(&timer->lock, flags);
+       guard(spinlock_irqsave)(&timer->lock);
 
        /* remember the current resolution */
        resolution = snd_timer_hw_resolution(timer);
@@ -919,10 +881,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
        snd_timer_process_callbacks(timer, &timer->ack_list_head);
 
        /* do we have any slow callbacks? */
-       use_work = !list_empty(&timer->sack_list_head);
-       spin_unlock_irqrestore(&timer->lock, flags);
-
-       if (use_work)
+       if (!list_empty(&timer->sack_list_head))
                queue_work(system_highpri_wq, &timer->task_work);
 }
 EXPORT_SYMBOL(snd_timer_interrupt);
@@ -988,7 +947,7 @@ static int snd_timer_free(struct snd_timer *timer)
        if (!timer)
                return 0;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        if (! list_empty(&timer->open_list_head)) {
                struct list_head *p, *n;
                struct snd_timer_instance *ti;
@@ -1000,7 +959,6 @@ static int snd_timer_free(struct snd_timer *timer)
                }
        }
        list_del(&timer->device_list);
-       mutex_unlock(&register_mutex);
 
        if (timer->private_free)
                timer->private_free(timer);
@@ -1025,7 +983,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
            !timer->hw.resolution && timer->hw.c_resolution == NULL)
                return -EINVAL;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        list_for_each_entry(timer1, &snd_timer_list, device_list) {
                if (timer1->tmr_class > timer->tmr_class)
                        break;
@@ -1046,11 +1004,9 @@ static int snd_timer_dev_register(struct snd_device *dev)
                if (timer1->tmr_subdevice < timer->tmr_subdevice)
                        continue;
                /* conflicts.. */
-               mutex_unlock(&register_mutex);
                return -EBUSY;
        }
        list_add_tail(&timer->device_list, &timer1->device_list);
-       mutex_unlock(&register_mutex);
        return 0;
 }
 
@@ -1059,20 +1015,18 @@ static int snd_timer_dev_disconnect(struct snd_device *device)
        struct snd_timer *timer = device->device_data;
        struct snd_timer_instance *ti;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        list_del_init(&timer->device_list);
        /* wake up pending sleepers */
        list_for_each_entry(ti, &timer->open_list_head, open_list) {
                if (ti->disconnect)
                        ti->disconnect(ti);
        }
-       mutex_unlock(&register_mutex);
        return 0;
 }
 
 void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp)
 {
-       unsigned long flags;
        unsigned long resolution = 0;
        struct snd_timer_instance *ti, *ts;
 
@@ -1083,7 +1037,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst
        if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
                       event > SNDRV_TIMER_EVENT_MRESUME))
                return;
-       spin_lock_irqsave(&timer->lock, flags);
+       guard(spinlock_irqsave)(&timer->lock);
        if (event == SNDRV_TIMER_EVENT_MSTART ||
            event == SNDRV_TIMER_EVENT_MCONTINUE ||
            event == SNDRV_TIMER_EVENT_MRESUME)
@@ -1095,7 +1049,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst
                        if (ts->ccallback)
                                ts->ccallback(ts, event, tstamp, resolution);
        }
-       spin_unlock_irqrestore(&timer->lock, flags);
 }
 EXPORT_SYMBOL(snd_timer_notify);
 
@@ -1248,7 +1201,7 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
        struct snd_timer_instance *ti;
        unsigned long resolution;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        list_for_each_entry(timer, &snd_timer_list, device_list) {
                if (timer->card && timer->card->shutdown)
                        continue;
@@ -1270,9 +1223,8 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
                                    timer->tmr_device, timer->tmr_subdevice);
                }
                snd_iprintf(buffer, "%s :", timer->name);
-               spin_lock_irq(&timer->lock);
-               resolution = snd_timer_hw_resolution(timer);
-               spin_unlock_irq(&timer->lock);
+               scoped_guard(spinlock_irq, &timer->lock)
+                       resolution = snd_timer_hw_resolution(timer);
                if (resolution)
                        snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
                                    resolution / 1000,
@@ -1288,7 +1240,6 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
                                                  SNDRV_TIMER_IFLG_RUNNING))
                                    ? "running" : "stopped");
        }
-       mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_timer_proc_entry;
@@ -1329,7 +1280,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
        struct snd_timer_read *r;
        int prev;
 
-       spin_lock(&tu->qlock);
+       guard(spinlock)(&tu->qlock);
        if (tu->qused > 0) {
                prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
                r = &tu->queue[prev];
@@ -1348,7 +1299,6 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
                tu->qused++;
        }
       __wake:
-       spin_unlock(&tu->qlock);
        snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
        wake_up(&tu->qchange_sleep);
 }
@@ -1372,7 +1322,6 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
 {
        struct snd_timer_user *tu = timeri->callback_data;
        struct snd_timer_tread64 r1;
-       unsigned long flags;
 
        if (event >= SNDRV_TIMER_EVENT_START &&
            event <= SNDRV_TIMER_EVENT_PAUSE)
@@ -1384,9 +1333,8 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
        r1.tstamp_sec = tstamp->tv_sec;
        r1.tstamp_nsec = tstamp->tv_nsec;
        r1.val = resolution;
-       spin_lock_irqsave(&tu->qlock, flags);
-       snd_timer_user_append_to_tqueue(tu, &r1);
-       spin_unlock_irqrestore(&tu->qlock, flags);
+       scoped_guard(spinlock_irqsave, &tu->qlock)
+               snd_timer_user_append_to_tqueue(tu, &r1);
        snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
        wake_up(&tu->qchange_sleep);
 }
@@ -1410,51 +1358,48 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
 
        memset(&r1, 0, sizeof(r1));
        memset(&tstamp, 0, sizeof(tstamp));
-       spin_lock(&tu->qlock);
-       if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
-                          (1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
-               spin_unlock(&tu->qlock);
-               return;
-       }
-       if (tu->last_resolution != resolution || ticks > 0) {
-               if (timer_tstamp_monotonic)
-                       ktime_get_ts64(&tstamp);
-               else
-                       ktime_get_real_ts64(&tstamp);
-       }
-       if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
-           tu->last_resolution != resolution) {
-               r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
+       scoped_guard(spinlock, &tu->qlock) {
+               if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
+                                  (1 << SNDRV_TIMER_EVENT_TICK))) == 0)
+                       return;
+               if (tu->last_resolution != resolution || ticks > 0) {
+                       if (timer_tstamp_monotonic)
+                               ktime_get_ts64(&tstamp);
+                       else
+                               ktime_get_real_ts64(&tstamp);
+               }
+               if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
+                   tu->last_resolution != resolution) {
+                       r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
+                       r1.tstamp_sec = tstamp.tv_sec;
+                       r1.tstamp_nsec = tstamp.tv_nsec;
+                       r1.val = resolution;
+                       snd_timer_user_append_to_tqueue(tu, &r1);
+                       tu->last_resolution = resolution;
+                       append++;
+               }
+               if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
+                       break;
+               if (ticks == 0)
+                       break;
+               if (tu->qused > 0) {
+                       prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
+                       r = &tu->tqueue[prev];
+                       if (r->event == SNDRV_TIMER_EVENT_TICK) {
+                               r->tstamp_sec = tstamp.tv_sec;
+                               r->tstamp_nsec = tstamp.tv_nsec;
+                               r->val += ticks;
+                               append++;
+                               break;
+                       }
+               }
+               r1.event = SNDRV_TIMER_EVENT_TICK;
                r1.tstamp_sec = tstamp.tv_sec;
                r1.tstamp_nsec = tstamp.tv_nsec;
-               r1.val = resolution;
+               r1.val = ticks;
                snd_timer_user_append_to_tqueue(tu, &r1);
-               tu->last_resolution = resolution;
                append++;
        }
-       if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
-               goto __wake;
-       if (ticks == 0)
-               goto __wake;
-       if (tu->qused > 0) {
-               prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
-               r = &tu->tqueue[prev];
-               if (r->event == SNDRV_TIMER_EVENT_TICK) {
-                       r->tstamp_sec = tstamp.tv_sec;
-                       r->tstamp_nsec = tstamp.tv_nsec;
-                       r->val += ticks;
-                       append++;
-                       goto __wake;
-               }
-       }
-       r1.event = SNDRV_TIMER_EVENT_TICK;
-       r1.tstamp_sec = tstamp.tv_sec;
-       r1.tstamp_nsec = tstamp.tv_nsec;
-       r1.val = ticks;
-       snd_timer_user_append_to_tqueue(tu, &r1);
-       append++;
-      __wake:
-       spin_unlock(&tu->qlock);
        if (append == 0)
                return;
        snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
@@ -1476,14 +1421,13 @@ static int realloc_user_queue(struct snd_timer_user *tu, int size)
                        return -ENOMEM;
        }
 
-       spin_lock_irq(&tu->qlock);
+       guard(spinlock_irq)(&tu->qlock);
        kfree(tu->queue);
        kfree(tu->tqueue);
        tu->queue_size = size;
        tu->queue = queue;
        tu->tqueue = tqueue;
        tu->qhead = tu->qtail = tu->qused = 0;
-       spin_unlock_irq(&tu->qlock);
 
        return 0;
 }
@@ -1519,12 +1463,12 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
        if (file->private_data) {
                tu = file->private_data;
                file->private_data = NULL;
-               mutex_lock(&tu->ioctl_lock);
-               if (tu->timeri) {
-                       snd_timer_close(tu->timeri);
-                       snd_timer_instance_free(tu->timeri);
+               scoped_guard(mutex, &tu->ioctl_lock) {
+                       if (tu->timeri) {
+                               snd_timer_close(tu->timeri);
+                               snd_timer_instance_free(tu->timeri);
+                       }
                }
-               mutex_unlock(&tu->ioctl_lock);
                snd_fasync_free(tu->fasync);
                kfree(tu->queue);
                kfree(tu->tqueue);
@@ -1559,7 +1503,7 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
 
        if (copy_from_user(&id, _tid, sizeof(id)))
                return -EFAULT;
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        if (id.dev_class < 0) {         /* first item */
                if (list_empty(&snd_timer_list))
                        snd_timer_user_zero_id(&id);
@@ -1636,7 +1580,6 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
                        snd_timer_user_zero_id(&id);
                }
        }
-       mutex_unlock(&register_mutex);
        if (copy_to_user(_tid, &id, sizeof(*_tid)))
                return -EFAULT;
        return 0;
@@ -1645,70 +1588,54 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
 static int snd_timer_user_ginfo(struct file *file,
                                struct snd_timer_ginfo __user *_ginfo)
 {
-       struct snd_timer_ginfo *ginfo;
+       struct snd_timer_ginfo *ginfo __free(kfree) = NULL;
        struct snd_timer_id tid;
        struct snd_timer *t;
        struct list_head *p;
-       int err = 0;
 
        ginfo = memdup_user(_ginfo, sizeof(*ginfo));
        if (IS_ERR(ginfo))
-               return PTR_ERR(ginfo);
+               return PTR_ERR(no_free_ptr(ginfo));
 
        tid = ginfo->tid;
        memset(ginfo, 0, sizeof(*ginfo));
        ginfo->tid = tid;
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        t = snd_timer_find(&tid);
-       if (t != NULL) {
-               ginfo->card = t->card ? t->card->number : -1;
-               if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
-                       ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
-               strscpy(ginfo->id, t->id, sizeof(ginfo->id));
-               strscpy(ginfo->name, t->name, sizeof(ginfo->name));
-               spin_lock_irq(&t->lock);
+       if (!t)
+               return -ENODEV;
+       ginfo->card = t->card ? t->card->number : -1;
+       if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
+               ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
+       strscpy(ginfo->id, t->id, sizeof(ginfo->id));
+       strscpy(ginfo->name, t->name, sizeof(ginfo->name));
+       scoped_guard(spinlock_irq, &t->lock)
                ginfo->resolution = snd_timer_hw_resolution(t);
-               spin_unlock_irq(&t->lock);
-               if (t->hw.resolution_min > 0) {
-                       ginfo->resolution_min = t->hw.resolution_min;
-                       ginfo->resolution_max = t->hw.resolution_max;
-               }
-               list_for_each(p, &t->open_list_head) {
-                       ginfo->clients++;
-               }
-       } else {
-               err = -ENODEV;
+       if (t->hw.resolution_min > 0) {
+               ginfo->resolution_min = t->hw.resolution_min;
+               ginfo->resolution_max = t->hw.resolution_max;
        }
-       mutex_unlock(&register_mutex);
-       if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
-               err = -EFAULT;
-       kfree(ginfo);
-       return err;
+       list_for_each(p, &t->open_list_head) {
+               ginfo->clients++;
+       }
+       if (copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
+               return -EFAULT;
+       return 0;
 }
 
 static int timer_set_gparams(struct snd_timer_gparams *gparams)
 {
        struct snd_timer *t;
-       int err;
 
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        t = snd_timer_find(&gparams->tid);
-       if (!t) {
-               err = -ENODEV;
-               goto _error;
-       }
-       if (!list_empty(&t->open_list_head)) {
-               err = -EBUSY;
-               goto _error;
-       }
-       if (!t->hw.set_period) {
-               err = -ENOSYS;
-               goto _error;
-       }
-       err = t->hw.set_period(t, gparams->period_num, gparams->period_den);
-_error:
-       mutex_unlock(&register_mutex);
-       return err;
+       if (!t)
+               return -ENODEV;
+       if (!list_empty(&t->open_list_head))
+               return -EBUSY;
+       if (!t->hw.set_period)
+               return -ENOSYS;
+       return t->hw.set_period(t, gparams->period_num, gparams->period_den);
 }
 
 static int snd_timer_user_gparams(struct file *file,
@@ -1734,10 +1661,10 @@ static int snd_timer_user_gstatus(struct file *file,
        tid = gstatus.tid;
        memset(&gstatus, 0, sizeof(gstatus));
        gstatus.tid = tid;
-       mutex_lock(&register_mutex);
+       guard(mutex)(&register_mutex);
        t = snd_timer_find(&tid);
        if (t != NULL) {
-               spin_lock_irq(&t->lock);
+               guard(spinlock_irq)(&t->lock);
                gstatus.resolution = snd_timer_hw_resolution(t);
                if (t->hw.precise_resolution) {
                        t->hw.precise_resolution(t, &gstatus.resolution_num,
@@ -1746,11 +1673,9 @@ static int snd_timer_user_gstatus(struct file *file,
                        gstatus.resolution_num = gstatus.resolution;
                        gstatus.resolution_den = 1000000000uL;
                }
-               spin_unlock_irq(&t->lock);
        } else {
                err = -ENODEV;
        }
-       mutex_unlock(&register_mutex);
        if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
                err = -EFAULT;
        return err;
@@ -1804,9 +1729,8 @@ static int snd_timer_user_info(struct file *file,
                               struct snd_timer_info __user *_info)
 {
        struct snd_timer_user *tu;
-       struct snd_timer_info *info;
+       struct snd_timer_info *info __free(kfree) = NULL;
        struct snd_timer *t;
-       int err = 0;
 
        tu = file->private_data;
        if (!tu->timeri)
@@ -1823,13 +1747,11 @@ static int snd_timer_user_info(struct file *file,
                info->flags |= SNDRV_TIMER_FLG_SLAVE;
        strscpy(info->id, t->id, sizeof(info->id));
        strscpy(info->name, t->name, sizeof(info->name));
-       spin_lock_irq(&t->lock);
-       info->resolution = snd_timer_hw_resolution(t);
-       spin_unlock_irq(&t->lock);
+       scoped_guard(spinlock_irq, &t->lock)
+               info->resolution = snd_timer_hw_resolution(t);
        if (copy_to_user(_info, info, sizeof(*_info)))
-               err = -EFAULT;
-       kfree(info);
-       return err;
+               return -EFAULT;
+       return 0;
 }
 
 static int snd_timer_user_params(struct file *file,
@@ -1887,45 +1809,47 @@ static int snd_timer_user_params(struct file *file,
                goto _end;
        }
        snd_timer_stop(tu->timeri);
-       spin_lock_irq(&t->lock);
-       tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
-                              SNDRV_TIMER_IFLG_EXCLUSIVE|
-                              SNDRV_TIMER_IFLG_EARLY_EVENT);
-       if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
-               tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
-       if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
-               tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
-       if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
-               tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
-       spin_unlock_irq(&t->lock);
+       scoped_guard(spinlock_irq, &t->lock) {
+               tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
+                                      SNDRV_TIMER_IFLG_EXCLUSIVE|
+                                      SNDRV_TIMER_IFLG_EARLY_EVENT);
+               if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
+                       tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
+               if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
+                       tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
+               if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
+                       tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
+       }
        if (params.queue_size > 0 &&
            (unsigned int)tu->queue_size != params.queue_size) {
                err = realloc_user_queue(tu, params.queue_size);
                if (err < 0)
                        goto _end;
        }
-       spin_lock_irq(&tu->qlock);
-       tu->qhead = tu->qtail = tu->qused = 0;
-       if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
-               if (tu->tread) {
-                       struct snd_timer_tread64 tread;
-                       memset(&tread, 0, sizeof(tread));
-                       tread.event = SNDRV_TIMER_EVENT_EARLY;
-                       tread.tstamp_sec = 0;
-                       tread.tstamp_nsec = 0;
-                       tread.val = 0;
-                       snd_timer_user_append_to_tqueue(tu, &tread);
-               } else {
-                       struct snd_timer_read *r = &tu->queue[0];
-                       r->resolution = 0;
-                       r->ticks = 0;
-                       tu->qused++;
-                       tu->qtail++;
+       scoped_guard(spinlock_irq, &tu->qlock) {
+               tu->qhead = tu->qtail = tu->qused = 0;
+               if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
+                       if (tu->tread) {
+                               struct snd_timer_tread64 tread;
+
+                               memset(&tread, 0, sizeof(tread));
+                               tread.event = SNDRV_TIMER_EVENT_EARLY;
+                               tread.tstamp_sec = 0;
+                               tread.tstamp_nsec = 0;
+                               tread.val = 0;
+                               snd_timer_user_append_to_tqueue(tu, &tread);
+                       } else {
+                               struct snd_timer_read *r = &tu->queue[0];
+
+                               r->resolution = 0;
+                               r->ticks = 0;
+                               tu->qused++;
+                               tu->qtail++;
+                       }
                }
+               tu->filter = params.filter;
+               tu->ticks = params.ticks;
        }
-       tu->filter = params.filter;
-       tu->ticks = params.ticks;
-       spin_unlock_irq(&tu->qlock);
        err = 0;
  _end:
        if (copy_to_user(_params, &params, sizeof(params)))
@@ -1948,9 +1872,8 @@ static int snd_timer_user_status32(struct file *file,
        status.resolution = snd_timer_resolution(tu->timeri);
        status.lost = tu->timeri->lost;
        status.overrun = tu->overrun;
-       spin_lock_irq(&tu->qlock);
-       status.queue = tu->qused;
-       spin_unlock_irq(&tu->qlock);
+       scoped_guard(spinlock_irq, &tu->qlock)
+               status.queue = tu->qused;
        if (copy_to_user(_status, &status, sizeof(status)))
                return -EFAULT;
        return 0;
@@ -1971,9 +1894,8 @@ static int snd_timer_user_status64(struct file *file,
        status.resolution = snd_timer_resolution(tu->timeri);
        status.lost = tu->timeri->lost;
        status.overrun = tu->overrun;
-       spin_lock_irq(&tu->qlock);
-       status.queue = tu->qused;
-       spin_unlock_irq(&tu->qlock);
+       scoped_guard(spinlock_irq, &tu->qlock)
+               status.queue = tu->qused;
        if (copy_to_user(_status, &status, sizeof(status)))
                return -EFAULT;
        return 0;
@@ -2131,12 +2053,9 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
                                 unsigned long arg)
 {
        struct snd_timer_user *tu = file->private_data;
-       long ret;
 
-       mutex_lock(&tu->ioctl_lock);
-       ret = __snd_timer_user_ioctl(file, cmd, arg, false);
-       mutex_unlock(&tu->ioctl_lock);
-       return ret;
+       guard(mutex)(&tu->ioctl_lock);
+       return __snd_timer_user_ioctl(file, cmd, arg, false);
 }
 
 static int snd_timer_user_fasync(int fd, struct file * file, int on)
@@ -2263,12 +2182,11 @@ static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait)
         poll_wait(file, &tu->qchange_sleep, wait);
 
        mask = 0;
-       spin_lock_irq(&tu->qlock);
+       guard(spinlock_irq)(&tu->qlock);
        if (tu->qused)
                mask |= EPOLLIN | EPOLLRDNORM;
        if (tu->disconnected)
                mask |= EPOLLERR;
-       spin_unlock_irq(&tu->qlock);
 
        return mask;
 }
index ee973b7b804499a52936100bdfcbe4235aeb4a28..4ae9eaeb5afb1a9351e4caf872f4562b298524fe 100644 (file)
@@ -115,10 +115,7 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
                                        unsigned long arg)
 {
        struct snd_timer_user *tu = file->private_data;
-       long ret;
 
-       mutex_lock(&tu->ioctl_lock);
-       ret = __snd_timer_user_ioctl_compat(file, cmd, arg);
-       mutex_unlock(&tu->ioctl_lock);
-       return ret;
+       guard(mutex)(&tu->ioctl_lock);
+       return __snd_timer_user_ioctl_compat(file, cmd, arg);
 }
index fe7911498cc4325a866a87328087c54a0a6c791a..fd6a68a5427886d11e443132a74568d933f2f163 100644 (file)
@@ -985,13 +985,11 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
        struct snd_ump_endpoint *ump = substream->rmidi->private_data;
        int dir = substream->stream;
        int group = ump->legacy_mapping[substream->number];
-       int err = 0;
+       int err;
 
-       mutex_lock(&ump->open_mutex);
-       if (ump->legacy_substreams[dir][group]) {
-               err = -EBUSY;
-               goto unlock;
-       }
+       guard(mutex)(&ump->open_mutex);
+       if (ump->legacy_substreams[dir][group])
+               return -EBUSY;
        if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
                if (!ump->legacy_out_opens) {
                        err = snd_rawmidi_kernel_open(&ump->core, 0,
@@ -999,17 +997,14 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
                                                      SNDRV_RAWMIDI_LFLG_APPEND,
                                                      &ump->legacy_out_rfile);
                        if (err < 0)
-                               goto unlock;
+                               return err;
                }
                ump->legacy_out_opens++;
                snd_ump_convert_reset(&ump->out_cvts[group]);
        }
-       spin_lock_irq(&ump->legacy_locks[dir]);
+       guard(spinlock_irq)(&ump->legacy_locks[dir]);
        ump->legacy_substreams[dir][group] = substream;
-       spin_unlock_irq(&ump->legacy_locks[dir]);
- unlock:
-       mutex_unlock(&ump->open_mutex);
-       return err;
+       return 0;
 }
 
 static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream)
@@ -1018,15 +1013,13 @@ static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream)
        int dir = substream->stream;
        int group = ump->legacy_mapping[substream->number];
 
-       mutex_lock(&ump->open_mutex);
-       spin_lock_irq(&ump->legacy_locks[dir]);
-       ump->legacy_substreams[dir][group] = NULL;
-       spin_unlock_irq(&ump->legacy_locks[dir]);
+       guard(mutex)(&ump->open_mutex);
+       scoped_guard(spinlock_irq, &ump->legacy_locks[dir])
+               ump->legacy_substreams[dir][group] = NULL;
        if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
                if (!--ump->legacy_out_opens)
                        snd_rawmidi_kernel_release(&ump->legacy_out_rfile);
        }
-       mutex_unlock(&ump->open_mutex);
        return 0;
 }
 
@@ -1078,12 +1071,11 @@ static int process_legacy_output(struct snd_ump_endpoint *ump,
        const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT;
        unsigned char c;
        int group, size = 0;
-       unsigned long flags;
 
        if (!ump->out_cvts || !ump->legacy_out_opens)
                return 0;
 
-       spin_lock_irqsave(&ump->legacy_locks[dir], flags);
+       guard(spinlock_irqsave)(&ump->legacy_locks[dir]);
        for (group = 0; group < SNDRV_UMP_MAX_GROUPS; group++) {
                substream = ump->legacy_substreams[dir][group];
                if (!substream)
@@ -1099,7 +1091,6 @@ static int process_legacy_output(struct snd_ump_endpoint *ump,
                        break;
                }
        }
-       spin_unlock_irqrestore(&ump->legacy_locks[dir], flags);
        return size;
 }
 
@@ -1109,18 +1100,16 @@ static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src,
        struct snd_rawmidi_substream *substream;
        unsigned char buf[16];
        unsigned char group;
-       unsigned long flags;
        const int dir = SNDRV_RAWMIDI_STREAM_INPUT;
        int size;
 
        size = snd_ump_convert_from_ump(src, buf, &group);
        if (size <= 0)
                return;
-       spin_lock_irqsave(&ump->legacy_locks[dir], flags);
+       guard(spinlock_irqsave)(&ump->legacy_locks[dir]);
        substream = ump->legacy_substreams[dir][group];
        if (substream)
                snd_rawmidi_receive(substream, buf, size);
-       spin_unlock_irqrestore(&ump->legacy_locks[dir], flags);
 }
 
 /* Fill ump->legacy_mapping[] for groups to be used for legacy rawmidi */
index 378d2c7c3d4af188a046feb238aeecc3179d477c..04a57f7be6ea42ae2891b70cf85f0b7048389665 100644 (file)
@@ -56,7 +56,7 @@ struct link_follower {
 
 static int follower_update(struct link_follower *follower)
 {
-       struct snd_ctl_elem_value *uctl;
+       struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
        int err, ch;
 
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
@@ -65,18 +65,16 @@ static int follower_update(struct link_follower *follower)
        uctl->id = follower->follower.id;
        err = follower->follower.get(&follower->follower, uctl);
        if (err < 0)
-               goto error;
+               return err;
        for (ch = 0; ch < follower->info.count; ch++)
                follower->vals[ch] = uctl->value.integer.value[ch];
- error:
-       kfree(uctl);
-       return err < 0 ? err : 0;
+       return 0;
 }
 
 /* get the follower ctl info and save the initial values */
 static int follower_init(struct link_follower *follower)
 {
-       struct snd_ctl_elem_info *uinfo;
+       struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
        int err;
 
        if (follower->info.count) {
@@ -91,22 +89,18 @@ static int follower_init(struct link_follower *follower)
                return -ENOMEM;
        uinfo->id = follower->follower.id;
        err = follower->follower.info(&follower->follower, uinfo);
-       if (err < 0) {
-               kfree(uinfo);
+       if (err < 0)
                return err;
-       }
        follower->info.type = uinfo->type;
        follower->info.count = uinfo->count;
        if (follower->info.count > 2  ||
            (follower->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
             follower->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
                pr_err("ALSA: vmaster: invalid follower element\n");
-               kfree(uinfo);
                return -EINVAL;
        }
        follower->info.min_val = uinfo->value.integer.min;
        follower->info.max_val = uinfo->value.integer.max;
-       kfree(uinfo);
 
        return follower_update(follower);
 }
@@ -341,7 +335,7 @@ static int master_get(struct snd_kcontrol *kcontrol,
 static int sync_followers(struct link_master *master, int old_val, int new_val)
 {
        struct link_follower *follower;
-       struct snd_ctl_elem_value *uval;
+       struct snd_ctl_elem_value *uval __free(kfree) = NULL;
 
        uval = kmalloc(sizeof(*uval), GFP_KERNEL);
        if (!uval)
@@ -353,7 +347,6 @@ static int sync_followers(struct link_master *master, int old_val, int new_val)
                master->val = new_val;
                follower_put_val(follower, uval);
        }
-       kfree(uval);
        return 0;
 }
 
index 1c65e0a3b13ce875f7416d3f63912f609080ffc0..892c4e29c0a348a9f7d87c826233d59b131c064f 100644 (file)
@@ -1830,7 +1830,6 @@ static int loopback_probe(struct platform_device *devptr)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int loopback_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
@@ -1847,11 +1846,7 @@ static int loopback_resume(struct device *pdev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume);
-#define LOOPBACK_PM_OPS        &loopback_pm
-#else
-#define LOOPBACK_PM_OPS        NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume);
 
 #define SND_LOOPBACK_DRIVER    "snd_aloop"
 
@@ -1859,7 +1854,7 @@ static struct platform_driver loopback_driver = {
        .probe          = loopback_probe,
        .driver         = {
                .name   = SND_LOOPBACK_DRIVER,
-               .pm     = LOOPBACK_PM_OPS,
+               .pm     = &loopback_pm,
        },
 };
 
index 4317677ba24aafbf76ec2e3f58de0164162c3d00..52ff6ac3f743564bd9e608d318f89f4a620aab72 100644 (file)
@@ -1098,7 +1098,6 @@ static int snd_dummy_probe(struct platform_device *devptr)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int snd_dummy_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
@@ -1115,11 +1114,7 @@ static int snd_dummy_resume(struct device *pdev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume);
-#define SND_DUMMY_PM_OPS       &snd_dummy_pm
-#else
-#define SND_DUMMY_PM_OPS       NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume);
 
 #define SND_DUMMY_DRIVER       "snd_dummy"
 
@@ -1127,7 +1122,7 @@ static struct platform_driver snd_dummy_driver = {
        .probe          = snd_dummy_probe,
        .driver         = {
                .name   = SND_DUMMY_DRIVER,
-               .pm     = SND_DUMMY_PM_OPS,
+               .pm     = &snd_dummy_pm,
        },
 };
 
index c7be1c395bcb3dda1d44df4d484a795046e3685e..7195cb49e00f8c10c786f1aff408e4304d005c6e 100644 (file)
@@ -176,7 +176,6 @@ static void pcsp_stop_beep(struct snd_pcsp *chip)
        pcspkr_stop_sound();
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int pcsp_suspend(struct device *dev)
 {
        struct snd_pcsp *chip = dev_get_drvdata(dev);
@@ -184,11 +183,7 @@ static int pcsp_suspend(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL);
-#define PCSP_PM_OPS    &pcsp_pm
-#else
-#define PCSP_PM_OPS    NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL);
 
 static void pcsp_shutdown(struct platform_device *dev)
 {
@@ -199,7 +194,7 @@ static void pcsp_shutdown(struct platform_device *dev)
 static struct platform_driver pcsp_platform_driver = {
        .driver         = {
                .name   = "pcspkr",
-               .pm     = PCSP_PM_OPS,
+               .pm     = &pcsp_pm,
        },
        .probe          = pcsp_probe,
        .shutdown       = pcsp_shutdown,
index 22b6c779682a3e5a565cfebdd1b74a878fa450fd..5973c25c2add62c84df89547fad9f8598f1c3e56 100644 (file)
@@ -175,6 +175,8 @@ config SND_FIREWIRE_MOTU
          * 8pre
          * 828mk3 (FireWire only)
          * 828mk3 (Hybrid)
+         * 896mk3 (FireWire only)
+         * 896mk3 (Hybrid)
          * Ultralite mk3 (FireWire only)
          * Ultralite mk3 (Hybrid)
          * Traveler mk3
index 7be17bca257f0ddba4799875c9250f96ba4e4b8a..c9f153f85ae6b6a29214847870a5599801209f50 100644 (file)
@@ -773,10 +773,14 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf,
        } else {
                unsigned int dbc_interval;
 
-               if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0)
-                       dbc_interval = s->ctx_data.tx.dbc_interval;
-               else
-                       dbc_interval = *data_blocks;
+               if (!(s->flags & CIP_DBC_IS_PAYLOAD_QUADLETS)) {
+                       if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0)
+                               dbc_interval = s->ctx_data.tx.dbc_interval;
+                       else
+                               dbc_interval = *data_blocks;
+               } else {
+                       dbc_interval = payload_length / sizeof(__be32);
+               }
 
                lost = dbc != ((*data_block_counter + dbc_interval) & 0xff);
        }
index b7ff44751ab93b625a154057535b532a65b46706..a1ed2e80f91a7cc07fecf55288a20a240d0900da 100644 (file)
@@ -37,6 +37,9 @@
  *     the value of current SYT_INTERVAL; e.g. initial value is not zero.
  * @CIP_UNAWARE_SYT: For outgoing packet, the value in SYT field of CIP is 0xffff.
  *     For incoming packet, the value in SYT field of CIP is not handled.
+ * @CIP_DBC_IS_PAYLOAD_QUADLETS: Available for incoming packet, and only effective with
+ *     CIP_DBC_IS_END_EVENT flag. The value of dbc field is the number of accumulated quadlets
+ *     in CIP payload, instead of the number of accumulated data blocks.
  */
 enum cip_flags {
        CIP_NONBLOCKING         = 0x00,
@@ -51,6 +54,7 @@ enum cip_flags {
        CIP_NO_HEADER           = 0x100,
        CIP_UNALIGHED_DBC       = 0x200,
        CIP_UNAWARE_SYT         = 0x400,
+       CIP_DBC_IS_PAYLOAD_QUADLETS = 0x800,
 };
 
 /**
index 8a0426920a760b838e56169dcea3c42d4ce7eeb1..7254fdfe046abd21b6087a1f4e511eccb35502a6 100644 (file)
@@ -261,6 +261,7 @@ int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu)
 
        if (motu->spec == &snd_motu_spec_828mk3_fw ||
            motu->spec == &snd_motu_spec_828mk3_hybrid ||
+           motu->spec == &snd_motu_spec_896mk3 ||
            motu->spec == &snd_motu_spec_traveler_mk3 ||
            motu->spec == &snd_motu_spec_track16)
                return detect_packet_formats_with_opt_ifaces(motu, data);
@@ -288,6 +289,14 @@ const struct snd_motu_spec snd_motu_spec_828mk3_hybrid = {
        .rx_fixed_pcm_chunks = {14, 14, 14},    // Additional 4 dummy chunks at higher rate.
 };
 
+const struct snd_motu_spec snd_motu_spec_896mk3 = {
+       .name = "896mk3",
+       .protocol_version = SND_MOTU_PROTOCOL_V3,
+       .flags = SND_MOTU_SPEC_COMMAND_DSP,
+       .tx_fixed_pcm_chunks = {18, 14, 10},
+       .rx_fixed_pcm_chunks = {18, 14, 10},
+};
+
 const struct snd_motu_spec snd_motu_spec_traveler_mk3 = {
        .name = "TravelerMk3",
        .protocol_version = SND_MOTU_PROTOCOL_V3,
index d73599eb7d5aae304d8c2fee9d46d470d3a01712..d14ab5dd5bea42f2bf0486e417297e7804ce0f71 100644 (file)
@@ -168,10 +168,12 @@ static const struct ieee1394_device_id motu_id_table[] = {
        SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite),
        SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre),
        SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3_fw), // FireWire only.
+       SND_MOTU_DEV_ENTRY(0x000017, &snd_motu_spec_896mk3), // FireWire only.
        SND_MOTU_DEV_ENTRY(0x000019, &snd_motu_spec_ultralite_mk3), // FireWire only.
        SND_MOTU_DEV_ENTRY(0x00001b, &snd_motu_spec_traveler_mk3),
        SND_MOTU_DEV_ENTRY(0x000030, &snd_motu_spec_ultralite_mk3), // Hybrid.
        SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3_hybrid), // Hybrid.
+       SND_MOTU_DEV_ENTRY(0x000037, &snd_motu_spec_896mk3), // Hybrid.
        SND_MOTU_DEV_ENTRY(0x000033, &snd_motu_spec_audio_express),
        SND_MOTU_DEV_ENTRY(0x000039, &snd_motu_spec_track16),
        SND_MOTU_DEV_ENTRY(0x000045, &snd_motu_spec_4pre),
index 3b1dc98a7be023231fe041611778e178bd8b8793..c66be0a89ccf174fcf298e8eacd21c084707d42b 100644 (file)
@@ -138,6 +138,7 @@ extern const struct snd_motu_spec snd_motu_spec_8pre;
 
 extern const struct snd_motu_spec snd_motu_spec_828mk3_fw;
 extern const struct snd_motu_spec snd_motu_spec_828mk3_hybrid;
+extern const struct snd_motu_spec snd_motu_spec_896mk3;
 extern const struct snd_motu_spec snd_motu_spec_traveler_mk3;
 extern const struct snd_motu_spec snd_motu_spec_ultralite_mk3;
 extern const struct snd_motu_spec snd_motu_spec_audio_express;
index f4a702def3979437faf2684a77351bb2a07c7600..00f7feb91f929515254ddf80c918e2dd93db2884 100644 (file)
@@ -177,6 +177,8 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
                        flags |= CIP_JUMBO_PAYLOAD;
                if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS)
                        flags |= CIP_WRONG_DBS;
+               if (oxfw->quirks & SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS)
+                       flags |= CIP_DBC_IS_END_EVENT | CIP_DBC_IS_PAYLOAD_QUADLETS;
        } else {
                conn = &oxfw->in_conn;
                c_dir = CMP_INPUT;
@@ -486,26 +488,57 @@ int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
                                enum avc_general_plug_dir dir,
                                struct snd_oxfw_stream_formation *formation)
 {
-       u8 *format;
-       unsigned int len;
        int err;
 
-       len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
-       format = kmalloc(len, GFP_KERNEL);
-       if (format == NULL)
-               return -ENOMEM;
+       if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
+               u8 *format;
+               unsigned int len;
 
-       err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
-       if (err < 0)
-               goto end;
-       if (len < 3) {
-               err = -EIO;
-               goto end;
+               len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+               format = kmalloc(len, GFP_KERNEL);
+               if (format == NULL)
+                       return -ENOMEM;
+
+               err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
+               if (err >= 0) {
+                       if (len < 3)
+                               err = -EIO;
+                       else
+                               err = snd_oxfw_stream_parse_format(format, formation);
+               }
+
+               kfree(format);
+       } else {
+               // Miglia Harmony Audio does not support Extended Stream Format Information
+               // command. Use the duplicated hard-coded format, instead.
+               unsigned int rate;
+               u8 *const *formats;
+               int i;
+
+               err = avc_general_get_sig_fmt(oxfw->unit, &rate, dir, 0);
+               if (err < 0)
+                       return err;
+
+               if (dir == AVC_GENERAL_PLUG_DIR_IN)
+                       formats = oxfw->rx_stream_formats;
+               else
+                       formats = oxfw->tx_stream_formats;
+
+               for (i = 0; (i < SND_OXFW_STREAM_FORMAT_ENTRIES); ++i) {
+                       if (!formats[i])
+                               continue;
+
+                       err = snd_oxfw_stream_parse_format(formats[i], formation);
+                       if (err < 0)
+                               continue;
+
+                       if (formation->rate == rate)
+                               break;
+               }
+               if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
+                       return -EIO;
        }
 
-       err = snd_oxfw_stream_parse_format(format, formation);
-end:
-       kfree(format);
        return err;
 }
 
@@ -515,7 +548,7 @@ end:
  * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
  * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
  */
-int snd_oxfw_stream_parse_format(u8 *format,
+int snd_oxfw_stream_parse_format(const u8 *format,
                                 struct snd_oxfw_stream_formation *formation)
 {
        unsigned int i, e, channels, type;
@@ -600,14 +633,33 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
        unsigned int i, eid;
        int err;
 
-       /* get format at current sampling rate */
-       err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
-       if (err < 0) {
-               dev_err(&oxfw->unit->device,
-               "fail to get current stream format for isoc %s plug %d:%d\n",
-                       (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
-                       pid, err);
-               goto end;
+       // get format at current sampling rate.
+       if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
+               err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
+               if (err < 0) {
+                       dev_err(&oxfw->unit->device,
+                               "fail to get current stream format for isoc %s plug %d:%d\n",
+                               (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
+                               pid, err);
+                       goto end;
+               }
+       } else {
+               // Miglia Harmony Audio does not support Extended Stream Format Information
+               // command. Use the hard-coded format, instead.
+               buf[0] = 0x90;
+               buf[1] = 0x40;
+               buf[2] = avc_stream_rate_table[0];
+               buf[3] = 0x00;
+               buf[4] = 0x01;
+
+               if (dir == AVC_GENERAL_PLUG_DIR_IN)
+                       buf[5] = 0x08;
+               else
+                       buf[5] = 0x02;
+
+               buf[6] = 0x06;
+
+               *len = 7;
        }
 
        /* parse and set stream format */
index 241a697ce26b2585f7271ef6e9ae0cbcadce879b..98ae0e8cba8790eead0a6fb0c3a102bb590cd13d 100644 (file)
@@ -21,6 +21,7 @@
 #define VENDOR_TASCAM          0x00022e
 #define OUI_STANTON            0x001260
 #define OUI_APOGEE             0x0003db
+#define OUI_OXFORD             0x0030e0
 
 #define MODEL_SATELLITE                0x00200f
 #define MODEL_SCS1M            0x001000
@@ -232,6 +233,11 @@ static int oxfw_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent
        if (err < 0)
                goto error;
 
+       if (entry->vendor_id == OUI_OXFORD && entry->model_id == 0x00f970) {
+               oxfw->quirks |= SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED |
+                               SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS;
+       }
+
        err = snd_oxfw_stream_discover(oxfw);
        if (err < 0)
                goto error;
@@ -330,6 +336,9 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
        //
        OXFW_DEV_ENTRY(VENDOR_GRIFFIN, 0x00f970, &griffin_firewave),
        OXFW_DEV_ENTRY(VENDOR_LACIE, 0x00f970, &lacie_speakers),
+       // Miglia HarmonyAudio (HA02). The numeric vendor ID is ASIC vendor and the model ID is the
+       // default value of ASIC.
+       OXFW_DEV_ENTRY(OUI_OXFORD, 0x00f970, NULL),
        // Behringer,F-Control Audio 202. The value of SYT field is not reliable at all.
        OXFW_DEV_ENTRY(VENDOR_BEHRINGER, 0x00fc22, NULL),
        // Loud Technologies, Tapco Link.FireWire 4x6. The value of SYT field is always 0xffff.
@@ -337,7 +346,6 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
        // Loud Technologies, Mackie Onyx Satellite. Although revised version of firmware is
        // installed to avoid the postpone, the value of SYT field is always 0xffff.
        OXFW_DEV_ENTRY(VENDOR_LOUD, MODEL_SATELLITE, NULL),
-       // Miglia HarmonyAudio. Not yet identified.
 
        //
        // OXFW971 devices:
index d728e451a25c6b98818ec31634d4896d58fbcb23..39ea9a6dde33a5c5a72a26741bc65c0330f9a001 100644 (file)
@@ -52,6 +52,11 @@ enum snd_oxfw_quirk {
        // performs media clock recovery voluntarily. In the recovery, the packets with NO_INFO
        // are ignored, thus driver should transfer packets with timestamp.
        SND_OXFW_QUIRK_VOLUNTARY_RECOVERY = 0x20,
+       // Miglia Harmony Audio does not support AV/C Stream Format Information command.
+       SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED = 0x40,
+       // Miglia Harmony Audio transmits CIP in which the value of dbc field expresses the number
+       // of accumulated payload quadlets including the packet.
+       SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS = 0x80,
 };
 
 /* This is an arbitrary number for convinience. */
@@ -136,7 +141,7 @@ struct snd_oxfw_stream_formation {
        unsigned int pcm;
        unsigned int midi;
 };
-int snd_oxfw_stream_parse_format(u8 *format,
+int snd_oxfw_stream_parse_format(const u8 *format,
                                 struct snd_oxfw_stream_formation *formation);
 int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
                                enum avc_general_plug_dir dir,
index 365c36fdf205854c12a6f1eda217b757f9e462bd..e9425213320eae71dbb5297c03195193fb437665 100644 (file)
@@ -127,15 +127,41 @@ static int i915_component_master_match(struct device *dev, int subcomponent,
 /* check whether Intel graphics is present and reachable */
 static int i915_gfx_present(struct pci_dev *hdac_pci)
 {
+       /* List of known platforms with no i915 support. */
+       static const struct pci_device_id denylist[] = {
+               /* CNL */
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a40), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a41), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a42), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a44), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a49), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4a), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4c), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a50), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a51), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a52), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a54), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a59), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5a), 0x030000, 0xff0000 },
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5c), 0x030000, 0xff0000 },
+               /* LKF */
+               { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9840), 0x030000, 0xff0000 },
+               {}
+       };
        struct pci_dev *display_dev = NULL;
 
        if (!gpu_bind || (gpu_bind < 0 && video_firmware_drivers_only()))
                return false;
 
        for_each_pci_dev(display_dev) {
-               if (display_dev->vendor == PCI_VENDOR_ID_INTEL &&
-                   (display_dev->class >> 16) == PCI_BASE_CLASS_DISPLAY &&
-                   connectivity_check(display_dev, hdac_pci)) {
+               if (display_dev->vendor != PCI_VENDOR_ID_INTEL ||
+                   (display_dev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
+                       continue;
+
+               if (pci_match_id(denylist, display_dev))
+                       continue;
+
+               if (connectivity_check(display_dev, hdac_pci)) {
                        pci_dev_put(display_dev);
                        return true;
                }
index 610ea7a33cd85adac277bfeae10a97494ed82a18..b53de020309f2bc1db45b88004986f628680cd54 100644 (file)
@@ -567,7 +567,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
        return 0;
 
  error:
-       dev_err(bus->dev, "Too many BDL entries: buffer=%d, period=%d\n",
+       dev_dbg(bus->dev, "Too many BDL entries: buffer=%d, period=%d\n",
                azx_dev->bufsize, period_bytes);
        return -EINVAL;
 }
index b57d72ea4503fa7504757eb6542b51e5b2e7b5e9..5f60658c6051c90bf06b42c8d39a53e3dd54c1f1 100644 (file)
@@ -23,6 +23,10 @@ static int ctrl_link_mask;
 module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
 MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
 
+static ulong ctrl_addr = 0x40000000;
+module_param_named(sdw_ctrl_addr, ctrl_addr, ulong, 0444);
+MODULE_PARM_DESC(sdw_ctrl_addr, "Intel SoundWire Controller _ADR");
+
 static bool is_link_enabled(struct fwnode_handle *fw_node, u8 idx)
 {
        struct fwnode_handle *link;
@@ -141,6 +145,9 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
        if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE)
                return AE_OK; /* keep going */
 
+       if (adr != ctrl_addr)
+               return AE_OK; /* keep going */
+
        /* found the correct SoundWire controller */
        info->handle = handle;
 
index 1d786bd5ce3e3ae8642bd96e748900baac6197a3..cd83aa864ea3e6e966140803a19818d663c49d72 100644 (file)
@@ -41,12 +41,9 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro
 static void reset_tlv(struct snd_ac97 *ac97, const char *name,
                      const unsigned int *tlv)
 {
-       struct snd_ctl_elem_id sid;
        struct snd_kcontrol *kctl;
-       memset(&sid, 0, sizeof(sid));
-       strcpy(sid.name, name);
-       sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-       kctl = snd_ctl_find_id(ac97->bus->card, &sid);
+
+       kctl = snd_ctl_find_id_mixer(ac97->bus->card, name);
        if (kctl && kctl->tlv.p)
                kctl->tlv.p = tlv;
 }
index 2378a39abaebec573a150184cf374d61636d7f7e..31e51e2df6557d6d946bca4c1b872f6e5a8905f8 100644 (file)
@@ -243,9 +243,7 @@ struct snd_ali {
        spinlock_t      reg_lock;
        spinlock_t      voice_alloc;
 
-#ifdef CONFIG_PM_SLEEP
-       struct snd_ali_image *image;
-#endif
+       struct snd_ali_image image;
 };
 
 static const struct pci_device_id snd_ali_ids[] = {
@@ -1824,18 +1822,13 @@ static int snd_ali_mixer(struct snd_ali *codec)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int ali_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ali *chip = card->private_data;
-       struct snd_ali_image *im;
+       struct snd_ali_image *im = &chip->image;
        int i, j;
 
-       im = chip->image;
-       if (!im)
-               return 0;
-
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        for (i = 0; i < chip->num_of_codecs; i++)
                snd_ac97_suspend(chip->ac97[i]);
@@ -1872,13 +1865,9 @@ static int ali_resume(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ali *chip = card->private_data;
-       struct snd_ali_image *im;
+       struct snd_ali_image *im = &chip->image;
        int i, j;
 
-       im = chip->image;
-       if (!im)
-               return 0;
-
        spin_lock_irq(&chip->reg_lock);
        
        for (i = 0; i < ALI_CHANNELS; i++) {
@@ -1908,11 +1897,7 @@ static int ali_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume);
-#define ALI_PM_OPS     &ali_pm
-#else
-#define ALI_PM_OPS     NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume);
 
 static void snd_ali_free(struct snd_card *card)
 {
@@ -2112,13 +2097,6 @@ static int snd_ali_create(struct snd_card *card,
                return err;
        }
 
-#ifdef CONFIG_PM_SLEEP
-       codec->image = devm_kmalloc(&pci->dev, sizeof(*codec->image),
-                                   GFP_KERNEL);
-       if (!codec->image)
-               dev_warn(card->dev, "can't allocate apm buffer\n");
-#endif
-
        snd_ali_enable_address_interrupt(codec);
        codec->hw_initialized = 1;
        return 0;
@@ -2181,7 +2159,7 @@ static struct pci_driver ali5451_driver = {
        .id_table = snd_ali_ids,
        .probe = snd_ali_probe,
        .driver = {
-               .pm = ALI_PM_OPS,
+               .pm = &ali_pm,
        },
 };                                
 
index c70aff0601205ede92ea2c97a2a999ed21ddbf42..c7c481203ef860a34891962d9bddac8a0e1423b2 100644 (file)
@@ -654,7 +654,6 @@ static int snd_als300_create(struct snd_card *card,
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int snd_als300_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
@@ -677,11 +676,7 @@ static int snd_als300_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume);
-#define SND_ALS300_PM_OPS      &snd_als300_pm
-#else
-#define SND_ALS300_PM_OPS      NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume);
 
 static int snd_als300_probe(struct pci_dev *pci,
                              const struct pci_device_id *pci_id)
@@ -739,7 +734,7 @@ static struct pci_driver als300_driver = {
        .id_table = snd_als300_ids,
        .probe = snd_als300_probe,
        .driver = {
-               .pm = SND_ALS300_PM_OPS,
+               .pm = &snd_als300_pm,
        },
 };
 
index f33aeb692a112ae4e9a539b63792857c024e2f8c..022473594c73ea581e797fa93d3836e7980d8cc1 100644 (file)
@@ -936,7 +936,6 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
        return snd_card_free_on_error(&pci->dev, __snd_card_als4000_probe(pci, pci_id));
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int snd_als4000_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
@@ -968,18 +967,14 @@ static int snd_als4000_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume);
-#define SND_ALS4000_PM_OPS     &snd_als4000_pm
-#else
-#define SND_ALS4000_PM_OPS     NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume);
 
 static struct pci_driver als4000_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_als4000_ids,
        .probe = snd_card_als4000_probe,
        .driver = {
-               .pm = SND_ALS4000_PM_OPS,
+               .pm = &snd_als4000_pm,
        },
 };
 
index 43d01f1847ed7d3a8301104422bee1b3e2290ef0..df2fef726d603bbcfa15b9328bf1532fe01bba83 100644 (file)
@@ -520,7 +520,6 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int snd_atiixp_aclink_down(struct atiixp *chip)
 {
        // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -530,7 +529,6 @@ static int snd_atiixp_aclink_down(struct atiixp *chip)
                     ATI_REG_CMD_POWERDOWN);
        return 0;
 }
-#endif
 
 /*
  * auto-detection of codecs
@@ -1454,7 +1452,6 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock,
 }
 
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1499,12 +1496,7 @@ static int snd_atiixp_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
-#define SND_ATIIXP_PM_OPS      &snd_atiixp_pm
-#else
-#define SND_ATIIXP_PM_OPS      NULL
-#endif /* CONFIG_PM_SLEEP */
-
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
 
 /*
  * proc interface for register dump
@@ -1634,7 +1626,7 @@ static struct pci_driver atiixp_driver = {
        .id_table = snd_atiixp_ids,
        .probe = snd_atiixp_probe,
        .driver = {
-               .pm = SND_ATIIXP_PM_OPS,
+               .pm = &snd_atiixp_pm,
        },
 };
 
index 8864c4c3c7e136b6fc7d6f61029ac481bff35743..eb569539f322543c5a15c53d0ea7dd7211cee600 100644 (file)
@@ -496,7 +496,6 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
 {
        // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -506,7 +505,6 @@ static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
                     ATI_REG_CMD_POWERDOWN);
        return 0;
 }
-#endif
 
 /*
  * auto-detection of codecs
@@ -1094,7 +1092,6 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
 }
 
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1128,11 +1125,7 @@ static int snd_atiixp_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
-#define SND_ATIIXP_PM_OPS      &snd_atiixp_pm
-#else
-#define SND_ATIIXP_PM_OPS      NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
 
 /*
  * proc interface for register dump
@@ -1258,7 +1251,7 @@ static struct pci_driver atiixp_modem_driver = {
        .id_table = snd_atiixp_ids,
        .probe = snd_atiixp_probe,
        .driver = {
-               .pm = SND_ATIIXP_PM_OPS,
+               .pm = &snd_atiixp_pm,
        },
 };
 
index b5c5a71c0ac3884f98a4b6a5636beb5ad43876f0..3a3de56b9b07a88163d4f05c742ff6636e4bcb6f 100644 (file)
 
 #define NUM_STREAM_CAPTURE_ANA 0
 
-typedef void (*snd_aw2_saa7146_it_cb) (void *);
+struct snd_pcm_substream;
+typedef void (*snd_aw2_saa7146_it_cb) (struct snd_pcm_substream *);
 
 struct snd_aw2_saa7146_cb_param {
        snd_aw2_saa7146_it_cb p_it_callback;
-       void *p_callback_param;
+       struct snd_pcm_substream *p_callback_param;
 };
 
 /* definition of the chip-specific record */
index 431f0026b507e2ce35f3e6f966ad03b4efe6946d..84989c291cd773357b5cd34f79dbcf02ab3478bd 100644 (file)
@@ -295,7 +295,6 @@ struct snd_azf3328 {
         * CONFIG_PM register storage below, but that's slightly difficult. */
        u16 shadow_reg_ctrl_6AH;
 
-#ifdef CONFIG_PM_SLEEP
        /* register value containers for power management
         * Note: not always full I/O range preserved (similar to Win driver!) */
        u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4];
@@ -303,7 +302,6 @@ struct snd_azf3328 {
        u32 saved_regs_mpu[AZF_ALIGN(AZF_IO_SIZE_MPU_PM) / 4];
        u32 saved_regs_opl3[AZF_ALIGN(AZF_IO_SIZE_OPL3_PM) / 4];
        u32 saved_regs_mixer[AZF_ALIGN(AZF_IO_SIZE_MIXER_PM) / 4];
-#endif
 };
 
 static const struct pci_device_id snd_azf3328_ids[] = {
@@ -2517,7 +2515,6 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        return snd_card_free_on_error(&pci->dev, __snd_azf3328_probe(pci, pci_id));
 }
 
-#ifdef CONFIG_PM_SLEEP
 static inline void
 snd_azf3328_suspend_regs(const struct snd_azf3328 *chip,
                         unsigned long io_addr, unsigned count, u32 *saved_regs)
@@ -2633,18 +2630,14 @@ snd_azf3328_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume);
-#define SND_AZF3328_PM_OPS     &snd_azf3328_pm
-#else
-#define SND_AZF3328_PM_OPS     NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume);
 
 static struct pci_driver azf3328_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_azf3328_ids,
        .probe = snd_azf3328_probe,
        .driver = {
-               .pm = SND_AZF3328_PM_OPS,
+               .pm = &snd_azf3328_pm,
        },
 };
 
index 08e34b184780187f66922448c40761e6281d84a2..36014501f7ed2e26595deee70aa8bc3a3e078f4b 100644 (file)
@@ -486,10 +486,8 @@ struct cmipci {
 
        spinlock_t reg_lock;
 
-#ifdef CONFIG_PM_SLEEP
        unsigned int saved_regs[0x20];
        unsigned char saved_mixers[0x20];
-#endif
 };
 
 
@@ -3260,7 +3258,6 @@ static int snd_cmipci_probe(struct pci_dev *pci,
        return err;
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -3324,18 +3321,14 @@ static int snd_cmipci_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume);
-#define SND_CMIPCI_PM_OPS      &snd_cmipci_pm
-#else
-#define SND_CMIPCI_PM_OPS      NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume);
 
 static struct pci_driver cmipci_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_cmipci_ids,
        .probe = snd_cmipci_probe,
        .driver = {
-               .pm = SND_CMIPCI_PM_OPS,
+               .pm = &snd_cmipci_pm,
        },
 };
        
index 0c9cadf7b3b802f99ad9d820f3e667c0952c41ab..0cc86e73cc62ec416fb5e4df9875956c382e67fd 100644 (file)
@@ -470,10 +470,7 @@ struct cs4281 {
 
        struct gameport *gameport;
 
-#ifdef CONFIG_PM_SLEEP
        u32 suspend_regs[SUSPEND_REGISTERS];
-#endif
-
 };
 
 static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
@@ -1897,8 +1894,6 @@ static int snd_cs4281_probe(struct pci_dev *pci,
 /*
  * Power Management
  */
-#ifdef CONFIG_PM_SLEEP
-
 static const int saved_regs[SUSPEND_REGISTERS] = {
        BA0_JSCTL,
        BA0_GPIOR,
@@ -1987,18 +1982,14 @@ static int cs4281_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume);
-#define CS4281_PM_OPS  &cs4281_pm
-#else
-#define CS4281_PM_OPS  NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume);
 
 static struct pci_driver cs4281_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_cs4281_ids,
        .probe = snd_cs4281_probe,
        .driver = {
-               .pm = CS4281_PM_OPS,
+               .pm = &cs4281_pm,
        },
 };
        
index d074727c3e21d3edf25f934b259e441a83738b1f..397900929aa659057bf5244154f47cd2dc56c887 100644 (file)
@@ -292,7 +292,7 @@ static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
        return 0;
 }
 
-int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
+int amixer_mgr_create(struct hw *hw, void **ramixer_mgr)
 {
        int err;
        struct amixer_mgr *amixer_mgr;
@@ -321,8 +321,9 @@ error:
        return err;
 }
 
-int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
+int amixer_mgr_destroy(void *ptr)
 {
+       struct amixer_mgr *amixer_mgr = ptr;
        rsc_mgr_uninit(&amixer_mgr->mgr);
        kfree(amixer_mgr);
        return 0;
@@ -446,7 +447,7 @@ static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
        return 0;
 }
 
-int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
+int sum_mgr_create(struct hw *hw, void **rsum_mgr)
 {
        int err;
        struct sum_mgr *sum_mgr;
@@ -475,8 +476,9 @@ error:
        return err;
 }
 
-int sum_mgr_destroy(struct sum_mgr *sum_mgr)
+int sum_mgr_destroy(void *ptr)
 {
+       struct sum_mgr *sum_mgr = ptr;
        rsc_mgr_uninit(&sum_mgr->mgr);
        kfree(sum_mgr);
        return 0;
index 4498e6139d0efa89c797f9f259b6a58cbec97cd6..8fc017da6bda8be8604222059108a31a42001ac1 100644 (file)
@@ -43,8 +43,8 @@ struct sum_mgr {
 };
 
 /* Constructor and destructor of daio resource manager */
-int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr);
-int sum_mgr_destroy(struct sum_mgr *sum_mgr);
+int sum_mgr_create(struct hw *hw, void **ptr);
+int sum_mgr_destroy(void *ptr);
 
 /* Define the descriptor of a amixer resource */
 struct amixer_rsc_ops;
@@ -89,7 +89,7 @@ struct amixer_mgr {
 };
 
 /* Constructor and destructor of amixer resource manager */
-int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr);
-int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr);
+int amixer_mgr_create(struct hw *hw, void **ramixer_mgr);
+int amixer_mgr_destroy(void *amixer_mgr);
 
 #endif /* CTAMIXER_H */
index fbdb8a3d5b8e559dba742a1cd282b14408a90d00..2a3e9d8ba7dbe71aa5222d9242e0702f0e7aa398 100644 (file)
@@ -105,23 +105,20 @@ static struct {
                            .public_name = "Mixer"}
 };
 
-typedef int (*create_t)(struct hw *, void **);
-typedef int (*destroy_t)(void *);
-
 static struct {
        int (*create)(struct hw *hw, void **rmgr);
        int (*destroy)(void *mgr);
 } rsc_mgr_funcs[NUM_RSCTYP] = {
-       [SRC]           = { .create     = (create_t)src_mgr_create,
-                           .destroy    = (destroy_t)src_mgr_destroy    },
-       [SRCIMP]        = { .create     = (create_t)srcimp_mgr_create,
-                           .destroy    = (destroy_t)srcimp_mgr_destroy },
-       [AMIXER]        = { .create     = (create_t)amixer_mgr_create,
-                           .destroy    = (destroy_t)amixer_mgr_destroy },
-       [SUM]           = { .create     = (create_t)sum_mgr_create,
-                           .destroy    = (destroy_t)sum_mgr_destroy    },
-       [DAIO]          = { .create     = (create_t)daio_mgr_create,
-                           .destroy    = (destroy_t)daio_mgr_destroy   }
+       [SRC]           = { .create     = src_mgr_create,
+                           .destroy    = src_mgr_destroy       },
+       [SRCIMP]        = { .create     = srcimp_mgr_create,
+                           .destroy    = srcimp_mgr_destroy    },
+       [AMIXER]        = { .create     = amixer_mgr_create,
+                           .destroy    = amixer_mgr_destroy    },
+       [SUM]           = { .create     = sum_mgr_create,
+                           .destroy    = sum_mgr_destroy       },
+       [DAIO]          = { .create     = daio_mgr_create,
+                           .destroy    = daio_mgr_destroy      }
 };
 
 static int
index 7fc720046ce293564e513ad78fccda687f45aa38..83aaf9441ef30f0f49cda656ff17aaf8be31859a 100644 (file)
@@ -684,7 +684,7 @@ static int daio_mgr_commit_write(struct daio_mgr *mgr)
        return 0;
 }
 
-int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr)
+int daio_mgr_create(struct hw *hw, void **rdaio_mgr)
 {
        int err, i;
        struct daio_mgr *daio_mgr;
@@ -738,8 +738,9 @@ error1:
        return err;
 }
 
-int daio_mgr_destroy(struct daio_mgr *daio_mgr)
+int daio_mgr_destroy(void *ptr)
 {
+       struct daio_mgr *daio_mgr = ptr;
        unsigned long flags;
 
        /* free daio input mapper list */
index bd6310f48013901ca0e562f5fe52eca386fc2c52..15147fe5f74a0b21a253d216762d1369fd5fef4f 100644 (file)
@@ -115,7 +115,7 @@ struct daio_mgr {
 };
 
 /* Constructor and destructor of daio resource manager */
-int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr);
-int daio_mgr_destroy(struct daio_mgr *daio_mgr);
+int daio_mgr_create(struct hw *hw, void **ptr);
+int daio_mgr_destroy(void *ptr);
 
 #endif /* CTDAIO_H */
index 4a94b4708a77e55f9ee81315b1d0f725c8cc3a33..159bd40080691715d71fb91bdedc74fe41440cc2 100644 (file)
@@ -540,7 +540,7 @@ static int src_mgr_commit_write(struct src_mgr *mgr)
        return 0;
 }
 
-int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr)
+int src_mgr_create(struct hw *hw, void **rsrc_mgr)
 {
        int err, i;
        struct src_mgr *src_mgr;
@@ -580,8 +580,9 @@ error1:
        return err;
 }
 
-int src_mgr_destroy(struct src_mgr *src_mgr)
+int src_mgr_destroy(void *ptr)
 {
+       struct src_mgr *src_mgr = ptr;
        rsc_mgr_uninit(&src_mgr->mgr);
        kfree(src_mgr);
 
@@ -821,7 +822,7 @@ static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry)
        return err;
 }
 
-int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr)
+int srcimp_mgr_create(struct hw *hw, void **rsrcimp_mgr)
 {
        int err;
        struct srcimp_mgr *srcimp_mgr;
@@ -866,8 +867,9 @@ error1:
        return err;
 }
 
-int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr)
+int srcimp_mgr_destroy(void *ptr)
 {
+       struct srcimp_mgr *srcimp_mgr = ptr;
        unsigned long flags;
 
        /* free src input mapper list */
index 1124daf50c9bea174296ad76714b0fc8bcbf9650..e6366cc6a7ae6aaaca8ae157b86514e7e8759c2d 100644 (file)
@@ -139,10 +139,10 @@ struct srcimp_mgr {
 };
 
 /* Constructor and destructor of SRC resource manager */
-int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr);
-int src_mgr_destroy(struct src_mgr *src_mgr);
+int src_mgr_create(struct hw *hw, void **ptr);
+int src_mgr_destroy(void *ptr);
 /* Constructor and destructor of SRCIMP resource manager */
-int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrc_mgr);
-int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr);
+int srcimp_mgr_create(struct hw *hw, void **ptr);
+int srcimp_mgr_destroy(void *ptr);
 
 #endif /* CTSRC_H */
index c70c3ac4e99a530d847f240c178d58dc4138a286..7484de255a3eda85b3dd5d20c4e6274ae7045da4 100644 (file)
@@ -34,7 +34,6 @@ static int get_firmware(const struct firmware **fw_entry,
        int err;
        char name[30];
 
-#ifdef CONFIG_PM_SLEEP
        if (chip->fw_cache[fw_index]) {
                dev_dbg(chip->card->dev,
                        "firmware requested: %s is cached\n",
@@ -42,7 +41,6 @@ static int get_firmware(const struct firmware **fw_entry,
                *fw_entry = chip->fw_cache[fw_index];
                return 0;
        }
-#endif
 
        dev_dbg(chip->card->dev,
                "firmware requested: %s\n", card_fw[fw_index].data);
@@ -51,10 +49,8 @@ static int get_firmware(const struct firmware **fw_entry,
        if (err < 0)
                dev_err(chip->card->dev,
                        "get_firmware(): Firmware not available (%d)\n", err);
-#ifdef CONFIG_PM_SLEEP
        else
                chip->fw_cache[fw_index] = *fw_entry;
-#endif
        return err;
 }
 
@@ -63,18 +59,13 @@ static int get_firmware(const struct firmware **fw_entry,
 static void free_firmware(const struct firmware *fw_entry,
                          struct echoaudio *chip)
 {
-#ifdef CONFIG_PM_SLEEP
        dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n");
-#else
-       release_firmware(fw_entry);
-#endif
 }
 
 
 
 static void free_firmware_cache(struct echoaudio *chip)
 {
-#ifdef CONFIG_PM_SLEEP
        int i;
 
        for (i = 0; i < 8 ; i++)
@@ -82,8 +73,6 @@ static void free_firmware_cache(struct echoaudio *chip)
                        release_firmware(chip->fw_cache[i]);
                        dev_dbg(chip->card->dev, "release_firmware(%d)\n", i);
                }
-
-#endif
 }
 
 
@@ -2146,8 +2135,6 @@ static int snd_echo_probe(struct pci_dev *pci,
 }
 
 
-#if defined(CONFIG_PM_SLEEP)
-
 static int snd_echo_suspend(struct device *dev)
 {
        struct echoaudio *chip = dev_get_drvdata(dev);
@@ -2237,11 +2224,7 @@ static int snd_echo_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
-#define SND_ECHO_PM_OPS        &snd_echo_pm
-#else
-#define SND_ECHO_PM_OPS        NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
 
 /******************************************************************************
        Everything starts and ends here
@@ -2253,7 +2236,7 @@ static struct pci_driver echo_driver = {
        .id_table = snd_echo_ids,
        .probe = snd_echo_probe,
        .driver = {
-               .pm = SND_ECHO_PM_OPS,
+               .pm = &snd_echo_pm,
        },
 };
 
index d51de3e4edfa8949bfd7bd754462a214604bc357..511f2fcc0fb92b395174b26aedbcf9cf0435b30f 100644 (file)
@@ -422,9 +422,7 @@ struct echoaudio {
        u32 __iomem *dsp_registers;             /* DSP's register base */
        u32 active_mask;                        /* Chs. active mask or
                                                 * punks out */
-#ifdef CONFIG_PM_SLEEP
        const struct firmware *fw_cache[8];     /* Cached firmwares */
-#endif
 
 #ifdef ECHOCARD_HAS_MIDI
        u16 mtc_state;                          /* State for MIDI input parsing state machine */
index cc3c79387194fea46c82582eefd5db952486c23e..18b4d4b4d38df04e4eb79813ade0f451c8a63c2d 100644 (file)
@@ -274,7 +274,6 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
                       chip->digital_mode == DIGITAL_MODE_ADAT))
                return -EINVAL;
 
-       clock = 0;
        control_reg = le32_to_cpu(chip->comm_page->control_register);
        control_reg &= E3G_CLOCK_CLEAR_MASK;
 
index 89210b2c734241c940381c35817fb8abf703bb30..18928b905939cf82afa404d699ab0abcd10b2a92 100644 (file)
@@ -1968,7 +1968,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
        outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int snd_ensoniq_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
@@ -2007,11 +2006,7 @@ static int snd_ensoniq_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume);
-#define SND_ENSONIQ_PM_OPS     &snd_ensoniq_pm
-#else
-#define SND_ENSONIQ_PM_OPS     NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume);
 
 static int snd_ensoniq_create(struct snd_card *card,
                              struct pci_dev *pci)
@@ -2380,7 +2375,7 @@ static struct pci_driver ens137x_driver = {
        .id_table = snd_audiopci_ids,
        .probe = snd_audiopci_probe,
        .driver = {
-               .pm = SND_ENSONIQ_PM_OPS,
+               .pm = &snd_ensoniq_pm,
        },
 };
        
index ec598ba1a8833fa982ac5db8b87aa9dd5601caf1..018a8d53ca53a43b6a3d76aa2fa91519e9c839d3 100644 (file)
@@ -216,9 +216,7 @@ struct es1938 {
 #ifdef SUPPORT_JOYSTICK
        struct gameport *gameport;
 #endif
-#ifdef CONFIG_PM_SLEEP
        unsigned char saved_regs[SAVED_REG_SIZE];
-#endif
 };
 
 static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
@@ -1395,7 +1393,6 @@ static void snd_es1938_chip_init(struct es1938 *chip)
        outb(0, SLDM_REG(chip, DMACLEAR));
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * PM support
  */
@@ -1461,11 +1458,7 @@ static int es1938_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);
-#define ES1938_PM_OPS  &es1938_pm
-#else
-#define ES1938_PM_OPS  NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);
 
 #ifdef SUPPORT_JOYSTICK
 static int snd_es1938_create_gameport(struct es1938 *chip)
@@ -1787,7 +1780,7 @@ static struct pci_driver es1938_driver = {
        .id_table = snd_es1938_ids,
        .probe = snd_es1938_probe,
        .driver = {
-               .pm = ES1938_PM_OPS,
+               .pm = &es1938_pm,
        },
 };
 
index 4bc0f53c223b7949cf9c33acee56166da301114b..c6c018b40c69f9bd1af9c4d361cb6258ae01b077 100644 (file)
@@ -473,9 +473,7 @@ struct esschan {
        /* linked list */
        struct list_head list;
 
-#ifdef CONFIG_PM_SLEEP
        u16 wc_map[4];
-#endif
 };
 
 struct es1968 {
@@ -526,9 +524,7 @@ struct es1968 {
        struct list_head substream_list;
        spinlock_t substream_lock;
 
-#ifdef CONFIG_PM_SLEEP
        u16 apu_map[NR_APUS][NR_APU_REGS];
-#endif
 
 #ifdef SUPPORT_JOYSTICK
        struct gameport *gameport;
@@ -689,9 +685,7 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat
 {
        if (snd_BUG_ON(channel >= NR_APUS))
                return;
-#ifdef CONFIG_PM_SLEEP
        chip->apu_map[channel][reg] = data;
-#endif
        reg |= (channel << 4);
        apu_index_set(chip, reg);
        apu_data_set(chip, data);
@@ -976,9 +970,7 @@ static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es
        /* set the wavecache control reg */
        wave_set_register(chip, es->apu[channel] << 3, tmpval);
 
-#ifdef CONFIG_PM_SLEEP
        es->wc_map[channel] = tmpval;
-#endif
 }
 
 
@@ -2356,7 +2348,6 @@ static void snd_es1968_start_irq(struct es1968 *chip)
        outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * PM support
  */
@@ -2418,11 +2409,7 @@ static int es1968_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume);
-#define ES1968_PM_OPS  &es1968_pm
-#else
-#define ES1968_PM_OPS  NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume);
 
 #ifdef SUPPORT_JOYSTICK
 #define JOYSTICK_ADDR  0x200
@@ -2852,7 +2839,7 @@ static struct pci_driver es1968_driver = {
        .id_table = snd_es1968_ids,
        .probe = snd_es1968_probe,
        .driver = {
-               .pm = ES1968_PM_OPS,
+               .pm = &es1968_pm,
        },
 };
 
index 62b3cb126c6d01291ab3ea811855c9410747f0df..7f4834c2d5e6b43b2339e8626f8a799637b2f997 100644 (file)
@@ -222,9 +222,7 @@ struct fm801 {
        struct snd_tea575x tea;
 #endif
 
-#ifdef CONFIG_PM_SLEEP
        u16 saved_regs[0x20];
-#endif
 };
 
 /*
@@ -1339,7 +1337,6 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
        return snd_card_free_on_error(&pci->dev, __snd_card_fm801_probe(pci, pci_id));
 }
 
-#ifdef CONFIG_PM_SLEEP
 static const unsigned char saved_regs[] = {
        FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC,
        FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2,
@@ -1396,18 +1393,14 @@ static int snd_fm801_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume);
-#define SND_FM801_PM_OPS       &snd_fm801_pm
-#else
-#define SND_FM801_PM_OPS       NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume);
 
 static struct pci_driver fm801_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_fm801_ids,
        .probe = snd_card_fm801_probe,
        .driver = {
-               .pm = SND_FM801_PM_OPS,
+               .pm = &snd_fm801_pm,
        },
 };
 
index ce2132ed6dbb94a8c71fbae6aea417b08ec0603a..f806636242ee902c4fd5ac58d5d60aa0b6befd89 100644 (file)
@@ -116,6 +116,9 @@ config SND_HDA_CS_DSP_CONTROLS
        tristate
        select FW_CS_DSP
 
+config SND_HDA_SCODEC_COMPONENT
+       tristate
+
 config SND_HDA_SCODEC_CS35L41_I2C
        tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
        depends on I2C
@@ -203,6 +206,7 @@ config SND_HDA_CODEC_REALTEK
        tristate "Build Realtek HD-audio codec support"
        select SND_HDA_GENERIC
        select SND_HDA_GENERIC_LEDS
+       select SND_HDA_SCODEC_COMPONENT
        help
          Say Y or M here to include Realtek HD-audio codec support in
          snd-hda-intel driver, such as ALC880.
index 793e296c3f64217b73eb58cefb902cb7caa094f6..13e04e1f65de2f661f79214a0f0a1d2bdba70965 100644 (file)
@@ -37,6 +37,7 @@ snd-hda-scodec-cs35l56-objs :=                cs35l56_hda.o
 snd-hda-scodec-cs35l56-i2c-objs :=     cs35l56_hda_i2c.o
 snd-hda-scodec-cs35l56-spi-objs :=     cs35l56_hda_spi.o
 snd-hda-cs-dsp-ctls-objs :=            hda_cs_dsp_ctl.o
+snd-hda-scodec-component-objs :=       hda_component.o
 snd-hda-scodec-tas2781-i2c-objs :=     tas2781_hda_i2c.o
 
 # common driver
@@ -67,6 +68,7 @@ obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
 obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o
+obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
 obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
 
 # this must be the last entry after codec drivers;
index e436d4dab317f05c20a8a806f14e07580bfcb2de..72ec872afb8d27de1d2b23288988bf4a5e4f4b88 100644 (file)
@@ -51,19 +51,30 @@ static const struct cs35l41_config cs35l41_config_table[] = {
        { "103C8A2E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 },
        { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE0", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE1", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE2", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE5", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8BE6", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE7", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE8", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
        { "103C8B3A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8CDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8CDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 3900, 24 },
        { "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
@@ -210,6 +221,7 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
        struct spi_device *spi;
        bool dsd_found;
        int ret;
+       int i;
 
        for (cfg = cs35l41_config_table; cfg->ssid; cfg++) {
                if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id))
@@ -295,16 +307,6 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
                        cs35l41->index = id == 0x40 ? 0 : 1;
        }
 
-       if (cfg->num_amps == 3)
-               /* 3 amps means a center channel, so no duplicate channels */
-               cs35l41->channel_index = 0;
-       else
-               /*
-                * if 4 amps, there are duplicate channels, so they need different indexes
-                * if 2 amps, no duplicate channels, channel_index would be 0
-                */
-               cs35l41->channel_index = cs35l41->index / 2;
-
        cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
                                                     cs35l41->index, GPIOD_OUT_LOW,
                                                     "cs35l41-reset");
@@ -312,6 +314,11 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
 
        hw_cfg->spk_pos = cfg->channel[cs35l41->index];
 
+       cs35l41->channel_index = 0;
+       for (i = 0; i < cs35l41->index; i++)
+               if (cfg->channel[i] == hw_cfg->spk_pos)
+                       cs35l41->channel_index++;
+
        if (cfg->boost_type == INTERNAL) {
                hw_cfg->bst_type = CS35L41_INT_BOOST;
                hw_cfg->bst_ind = cfg->boost_ind_nanohenry;
@@ -335,6 +342,42 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
        return 0;
 }
 
+/*
+ * Systems 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system - each speaker has
+ * its own speaker id.
+ */
+static int hp_i2c_int_2amp_dual_spkid(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                                     const char *hid)
+{
+       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+       /* If _DSD exists for this laptop, we cannot support it through here */
+       if (acpi_dev_has_props(cs35l41->dacpi))
+               return -ENOENT;
+
+       /* check I2C address to assign the index */
+       cs35l41->index = id == 0x40 ? 0 : 1;
+       cs35l41->channel_index = 0;
+       cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+       if (cs35l41->index == 0)
+               cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 1);
+       else
+               cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+       hw_cfg->spk_pos = cs35l41->index;
+       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+       hw_cfg->gpio2.valid = true;
+       hw_cfg->valid = true;
+
+       hw_cfg->bst_type = CS35L41_INT_BOOST;
+       hw_cfg->bst_ind = 1000;
+       hw_cfg->bst_ipk = 4100;
+       hw_cfg->bst_cap = 24;
+       hw_cfg->gpio1.func = CS35L41_NOT_USED;
+       hw_cfg->gpio1.valid = true;
+
+       return 0;
+}
+
 /*
  * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
  * And devices created by serial-multi-instantiate don't have their device struct
@@ -392,19 +435,34 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
        { "CSC3551", "103C8A2E", generic_dsd_config },
        { "CSC3551", "103C8A30", generic_dsd_config },
        { "CSC3551", "103C8A31", generic_dsd_config },
+       { "CSC3551", "103C8A6E", generic_dsd_config },
        { "CSC3551", "103C8BB3", generic_dsd_config },
        { "CSC3551", "103C8BB4", generic_dsd_config },
+       { "CSC3551", "103C8BDD", generic_dsd_config },
+       { "CSC3551", "103C8BDE", generic_dsd_config },
        { "CSC3551", "103C8BDF", generic_dsd_config },
        { "CSC3551", "103C8BE0", generic_dsd_config },
        { "CSC3551", "103C8BE1", generic_dsd_config },
        { "CSC3551", "103C8BE2", generic_dsd_config },
-       { "CSC3551", "103C8BE9", generic_dsd_config },
-       { "CSC3551", "103C8BDD", generic_dsd_config },
-       { "CSC3551", "103C8BDE", generic_dsd_config },
        { "CSC3551", "103C8BE3", generic_dsd_config },
        { "CSC3551", "103C8BE5", generic_dsd_config },
        { "CSC3551", "103C8BE6", generic_dsd_config },
+       { "CSC3551", "103C8BE7", generic_dsd_config },
+       { "CSC3551", "103C8BE8", generic_dsd_config },
+       { "CSC3551", "103C8BE9", generic_dsd_config },
        { "CSC3551", "103C8B3A", generic_dsd_config },
+       { "CSC3551", "103C8C15", generic_dsd_config },
+       { "CSC3551", "103C8C16", generic_dsd_config },
+       { "CSC3551", "103C8C17", generic_dsd_config },
+       { "CSC3551", "103C8C4F", generic_dsd_config },
+       { "CSC3551", "103C8C50", generic_dsd_config },
+       { "CSC3551", "103C8C51", generic_dsd_config },
+       { "CSC3551", "103C8C66", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C67", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C68", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C6A", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8CDD", generic_dsd_config },
+       { "CSC3551", "103C8CDE", generic_dsd_config },
        { "CSC3551", "104312AF", generic_dsd_config },
        { "CSC3551", "10431433", generic_dsd_config },
        { "CSC3551", "10431463", generic_dsd_config },
index 5ad76d6914c31e538cfb906db5b955b4f16d72ba..41974b3897a723ccd429a8e51032245d35ec2e48 100644 (file)
@@ -459,13 +459,15 @@ static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
 
        if (preloaded_fw_ver) {
                snprintf(base_name, sizeof(base_name),
-                        "cirrus/cs35l56-%02x%s-%06x-dsp1-misc",
+                        "cirrus/cs35l%02x-%02x%s-%06x-dsp1-misc",
+                        cs35l56->base.type,
                         cs35l56->base.rev,
                         cs35l56->base.secured ? "-s" : "",
                         preloaded_fw_ver & 0xffffff);
        } else {
                snprintf(base_name, sizeof(base_name),
-                        "cirrus/cs35l56-%02x%s-dsp1-misc",
+                        "cirrus/cs35l%02x-%02x%s-dsp1-misc",
+                        cs35l56->base.type,
                         cs35l56->base.rev,
                         cs35l56->base.secured ? "-s" : "");
        }
@@ -852,9 +854,10 @@ static int cs35l56_hda_system_resume(struct device *dev)
        return 0;
 }
 
-static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id)
+static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
 {
        u32 values[HDA_MAX_COMPONENTS];
+       char hid_string[8];
        struct acpi_device *adev;
        const char *property, *sub;
        size_t nval;
@@ -865,7 +868,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id)
         * the serial-multi-instantiate driver, so lookup the node by HID
         */
        if (!ACPI_COMPANION(cs35l56->base.dev)) {
-               adev = acpi_dev_get_first_match_dev("CSC3556", NULL, -1);
+               snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid);
+               adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1);
                if (!adev) {
                        dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",
                                dev_name(cs35l56->base.dev));
@@ -953,14 +957,14 @@ err:
        return ret;
 }
 
-int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id)
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
 {
        int ret;
 
        mutex_init(&cs35l56->base.irq_lock);
        dev_set_drvdata(cs35l56->base.dev, cs35l56);
 
-       ret = cs35l56_hda_read_acpi(cs35l56, id);
+       ret = cs35l56_hda_read_acpi(cs35l56, hid, id);
        if (ret)
                goto err;
 
index 6e5bc5397db5f894863608b74e71c2e245433338..464e4aa63cd1b18c380571031a6148733eb4edb4 100644 (file)
@@ -42,7 +42,7 @@ struct cs35l56_hda {
 
 extern const struct dev_pm_ops cs35l56_hda_pm_ops;
 
-int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id);
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id);
 void cs35l56_hda_remove(struct device *dev);
 
 #endif /*__CS35L56_HDA_H__*/
index a9ef6d86de8397ece6aaebce969199294f39ce32..13beee807308f1763145cc1f9c1590e427236dc6 100644 (file)
@@ -13,6 +13,7 @@
 
 static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(clt);
        struct cs35l56_hda *cs35l56;
        int ret;
 
@@ -33,7 +34,7 @@ static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
                return ret;
        }
 
-       ret = cs35l56_hda_common_probe(cs35l56, clt->addr);
+       ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, clt->addr);
        if (ret)
                return ret;
        ret = cs35l56_irq_request(&cs35l56->base, clt->irq);
@@ -49,7 +50,9 @@ static void cs35l56_hda_i2c_remove(struct i2c_client *clt)
 }
 
 static const struct i2c_device_id cs35l56_hda_i2c_id[] = {
-       { "cs35l56-hda", 0 },
+       { "cs35l54-hda", 0x3554 },
+       { "cs35l56-hda", 0x3556 },
+       { "cs35l57-hda", 0x3557 },
        {}
 };
 
index 080426de90830eb148eacf08f41bea1b5d57205a..a3b2fa76663d3685cf404e59785cdc00c502e493 100644 (file)
@@ -13,6 +13,7 @@
 
 static int cs35l56_hda_spi_probe(struct spi_device *spi)
 {
+       const struct spi_device_id *id = spi_get_device_id(spi);
        struct cs35l56_hda *cs35l56;
        int ret;
 
@@ -33,7 +34,7 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi)
                return ret;
        }
 
-       ret = cs35l56_hda_common_probe(cs35l56, spi_get_chipselect(spi, 0));
+       ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, spi_get_chipselect(spi, 0));
        if (ret)
                return ret;
        ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
@@ -49,7 +50,9 @@ static void cs35l56_hda_spi_remove(struct spi_device *spi)
 }
 
 static const struct spi_device_id cs35l56_hda_spi_id[] = {
-       { "cs35l56-hda", 0 },
+       { "cs35l54-hda", 0x3554 },
+       { "cs35l56-hda", 0x3556 },
+       { "cs35l57-hda", 0x3557 },
        {}
 };
 
index e63621bcb21427b6ecc1e5516f37ca38ac1cef2f..e51d475725576b4c88bfd50f504288cd6f96a719 100644 (file)
@@ -231,7 +231,6 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
        codec->beep = beep;
 
        INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
-       mutex_init(&beep->mutex);
 
        input_dev = input_allocate_device();
        if (!input_dev) {
index db76e3ddba65445bc8e47257436d6f6cb51df142..923ea862446a01448ad3422ca76f8116503bee63 100644 (file)
@@ -27,7 +27,6 @@ struct hda_beep {
        unsigned int playing:1;
        unsigned int keep_power_at_enable:1;    /* set by driver */
        struct work_struct beep_work; /* scheduled task for beep event */
-       struct mutex mutex;
        void (*power_hook)(struct hda_beep *beep, bool on);
 };
 
index 12f02cdc965942ef85c8bac1e0f15f680604ca68..2cac337f526322270e7afa25fd2119f7aa3bf8af 100644 (file)
@@ -3313,7 +3313,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
        list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
                int stream;
 
-               for (stream = 0; stream < 2; stream++) {
+               for_each_pcm_streams(stream) {
                        struct hda_pcm_stream *info = &cpcm->stream[stream];
 
                        if (!info->substreams)
diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c
new file mode 100644 (file)
index 0000000..cd299d7
--- /dev/null
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio Component Binding Interface
+ *
+ * Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
+ *                     Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/acpi.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/hda_codec.h>
+#include "hda_component.h"
+#include "hda_local.h"
+
+#ifdef CONFIG_ACPI
+void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps,
+                                     acpi_handle handle, u32 event, void *data)
+{
+       int i;
+
+       for (i = 0; i < num_comps; i++) {
+               if (comps[i].dev && comps[i].acpi_notify)
+                       comps[i].acpi_notify(acpi_device_handle(comps[i].adev), event,
+                                            comps[i].dev);
+       }
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, SND_HDA_SCODEC_COMPONENT);
+
+int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+                                                 struct hda_component *comps, int num_comps,
+                                                 acpi_notify_handler handler, void *data)
+{
+       bool support_notifications = false;
+       struct acpi_device *adev;
+       int ret;
+       int i;
+
+       adev = comps[0].adev;
+       if (!acpi_device_handle(adev))
+               return 0;
+
+       for (i = 0; i < num_comps; i++)
+               support_notifications = support_notifications ||
+                       comps[i].acpi_notifications_supported;
+
+       if (support_notifications) {
+               ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
+                                                 handler, data);
+               if (ret < 0) {
+                       codec_warn(cdc, "Failed to install notify handler: %d\n", ret);
+                       return 0;
+               }
+
+               codec_dbg(cdc, "Notify handler installed\n");
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, SND_HDA_SCODEC_COMPONENT);
+
+void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+                                                    struct hda_component *comps,
+                                                    acpi_notify_handler handler)
+{
+       struct acpi_device *adev;
+       int ret;
+
+       adev = comps[0].adev;
+       if (!acpi_device_handle(adev))
+               return;
+
+       ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, handler);
+       if (ret < 0)
+               codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, SND_HDA_SCODEC_COMPONENT);
+#endif /* ifdef CONFIG_ACPI */
+
+void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, int action)
+{
+       int i;
+
+       for (i = 0; i < num_comps; i++) {
+               if (comps[i].dev && comps[i].pre_playback_hook)
+                       comps[i].pre_playback_hook(comps[i].dev, action);
+       }
+       for (i = 0; i < num_comps; i++) {
+               if (comps[i].dev && comps[i].playback_hook)
+                       comps[i].playback_hook(comps[i].dev, action);
+       }
+       for (i = 0; i < num_comps; i++) {
+               if (comps[i].dev && comps[i].post_playback_hook)
+                       comps[i].post_playback_hook(comps[i].dev, action);
+       }
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, SND_HDA_SCODEC_COMPONENT);
+
+struct hda_scodec_match {
+       const char *bus;
+       const char *hid;
+       const char *match_str;
+       int index;
+};
+
+/* match the device name in a slightly relaxed manner */
+static int hda_comp_match_dev_name(struct device *dev, void *data)
+{
+       struct hda_scodec_match *p = data;
+       const char *d = dev_name(dev);
+       int n = strlen(p->bus);
+       char tmp[32];
+
+       /* check the bus name */
+       if (strncmp(d, p->bus, n))
+               return 0;
+       /* skip the bus number */
+       if (isdigit(d[n]))
+               n++;
+       /* the rest must be exact matching */
+       snprintf(tmp, sizeof(tmp), p->match_str, p->hid, p->index);
+       return !strcmp(d + n, tmp);
+}
+
+int hda_component_manager_init(struct hda_codec *cdc,
+                              struct hda_component *comps, int count,
+                              const char *bus, const char *hid,
+                              const char *match_str,
+                              const struct component_master_ops *ops)
+{
+       struct device *dev = hda_codec_dev(cdc);
+       struct component_match *match = NULL;
+       struct hda_scodec_match *sm;
+       int ret, i;
+
+       for (i = 0; i < count; i++) {
+               sm = devm_kmalloc(dev, sizeof(*sm), GFP_KERNEL);
+               if (!sm)
+                       return -ENOMEM;
+
+               sm->bus = bus;
+               sm->hid = hid;
+               sm->match_str = match_str;
+               sm->index = i;
+               comps[i].codec = cdc;
+               component_match_add(dev, &match, hda_comp_match_dev_name, sm);
+       }
+
+       ret = component_master_add_with_match(dev, ops, match);
+       if (ret)
+               codec_err(cdc, "Fail to register component aggregator %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, SND_HDA_SCODEC_COMPONENT);
+
+void hda_component_manager_free(struct hda_codec *cdc,
+                               const struct component_master_ops *ops)
+{
+       struct device *dev = hda_codec_dev(cdc);
+
+       component_master_del(dev, ops);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, SND_HDA_SCODEC_COMPONENT);
+
+MODULE_DESCRIPTION("HD Audio component binding library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
index bbd6f0ed16c13d09aac393059b84dd9419893979..c80a66691b5d86c5b27f99abfe127a2f1fafaf7f 100644 (file)
@@ -6,8 +6,12 @@
  *                    Cirrus Logic International Semiconductor Ltd.
  */
 
+#ifndef __HDA_COMPONENT_H__
+#define __HDA_COMPONENT_H__
+
 #include <linux/acpi.h>
 #include <linux/component.h>
+#include <sound/hda_codec.h>
 
 #define HDA_MAX_COMPONENTS     4
 #define HDA_MAX_NAME_SIZE      50
@@ -23,3 +27,64 @@ struct hda_component {
        void (*playback_hook)(struct device *dev, int action);
        void (*post_playback_hook)(struct device *dev, int action);
 };
+
+#ifdef CONFIG_ACPI
+void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps,
+                                     acpi_handle handle, u32 event, void *data);
+int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+                                                 struct hda_component *comps, int num_comps,
+                                                 acpi_notify_handler handler, void *data);
+void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+                                                    struct hda_component *comps,
+                                                    acpi_notify_handler handler);
+#else
+static inline void hda_component_acpi_device_notify(struct hda_component *comps,
+                                                   int num_comps,
+                                                   acpi_handle handle,
+                                                   u32 event,
+                                                   void *data)
+{
+}
+
+static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+                                                               struct hda_component *comps,
+                                                               int num_comps,
+                                                               acpi_notify_handler handler,
+                                                               void *data)
+
+{
+       return 0;
+}
+
+static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+                                                                  struct hda_component *comps,
+                                                                  acpi_notify_handler handler)
+{
+}
+#endif /* ifdef CONFIG_ACPI */
+
+void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps,
+                                        int action);
+
+int hda_component_manager_init(struct hda_codec *cdc,
+                              struct hda_component *comps, int count,
+                              const char *bus, const char *hid,
+                              const char *match_str,
+                              const struct component_master_ops *ops);
+
+void hda_component_manager_free(struct hda_codec *cdc,
+                               const struct component_master_ops *ops);
+
+static inline int hda_component_manager_bind(struct hda_codec *cdc,
+                                            struct hda_component *comps)
+{
+       return component_bind_all(hda_codec_dev(cdc), comps);
+}
+
+static inline void hda_component_manager_unbind(struct hda_codec *cdc,
+                                              struct hda_component *comps)
+{
+       component_unbind_all(hda_codec_dev(cdc), comps);
+}
+
+#endif /* ifndef __HDA_COMPONENT_H__ */
index efe98f6f19a373b9c343861cf9bdc2039885d7e2..206306a0eb827abaf0030a668959bba33f882fe5 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <sound/core.h>
 #include <sound/initval.h>
+#include <sound/pcm_params.h>
 #include "hda_controller.h"
 #include "hda_local.h"
 
@@ -108,6 +109,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx *chip = apcm->chip;
        struct azx_dev *azx_dev = get_azx_dev(substream);
+       struct hdac_stream *hdas = azx_stream(azx_dev);
        int ret = 0;
 
        trace_azx_pcm_hw_params(chip, azx_dev);
@@ -117,9 +119,15 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
                goto unlock;
        }
 
-       azx_dev->core.bufsize = 0;
-       azx_dev->core.period_bytes = 0;
-       azx_dev->core.format_val = 0;
+       /* Set up BDLEs here, return -ENOMEM if too many BDLEs are required */
+       hdas->bufsize = params_buffer_bytes(hw_params);
+       hdas->period_bytes = params_period_bytes(hw_params);
+       hdas->format_val = 0;
+       hdas->no_period_wakeup =
+               (hw_params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+               (hw_params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
+       if (snd_hdac_stream_setup_periods(hdas) < 0)
+               ret = -ENOMEM;
 
 unlock:
        dsp_unlock(azx_dev);
index a1facdb98d9a00a4236ff06c0f64700a0facd1cc..a17c36a36aa5375fd8295911a2ffc707cb14263e 100644 (file)
@@ -133,7 +133,6 @@ struct alc_spec {
        u8 alc_mute_keycode_map[1];
 
        /* component binding */
-       struct component_match *match;
        struct hda_component comps[HDA_MAX_COMPONENTS];
 };
 
@@ -2646,6 +2645,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
@@ -6696,6 +6696,60 @@ static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec,
        }
 }
 
+static void alc285_fixup_hp_envy_x360(struct hda_codec *codec,
+                                     const struct hda_fixup *fix,
+                                     int action)
+{
+       static const struct coef_fw coefs[] = {
+               WRITE_COEF(0x08, 0x6a0c), WRITE_COEF(0x0d, 0xa023),
+               WRITE_COEF(0x10, 0x0320), WRITE_COEF(0x1a, 0x8c03),
+               WRITE_COEF(0x25, 0x1800), WRITE_COEF(0x26, 0x003a),
+               WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb014),
+               WRITE_COEF(0x2b, 0x1dfe), WRITE_COEF(0x37, 0xfe15),
+               WRITE_COEF(0x38, 0x7909), WRITE_COEF(0x45, 0xd489),
+               WRITE_COEF(0x46, 0x00f4), WRITE_COEF(0x4a, 0x21e0),
+               WRITE_COEF(0x66, 0x03f0), WRITE_COEF(0x67, 0x1000),
+               WRITE_COEF(0x6e, 0x1005), { }
+       };
+
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x12, 0xb7a60130 },  /* Internal microphone*/
+               { 0x14, 0x90170150 },  /* B&O soundbar speakers */
+               { 0x17, 0x90170153 },  /* Side speakers */
+               { 0x19, 0x03a11040 },  /* Headset microphone */
+               { }
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+
+               /* Fixes volume control problem for side speakers */
+               alc295_fixup_disable_dac3(codec, fix, action);
+
+               /* Fixes no sound from headset speaker */
+               snd_hda_codec_amp_stereo(codec, 0x21, HDA_OUTPUT, 0, -1, 0);
+
+               /* Auto-enable headset mic when plugged */
+               snd_hda_jack_set_gating_jack(codec, 0x19, 0x21);
+
+               /* Headset mic volume enhancement */
+               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREF50);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               alc_process_coef_fw(codec, coefs);
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               rename_ctl(codec, "Bass Speaker Playback Volume",
+                          "B&O-Tuned Playback Volume");
+               rename_ctl(codec, "Front Playback Switch",
+                          "B&O Soundbar Playback Switch");
+               rename_ctl(codec, "Bass Speaker Playback Switch",
+                          "Side Speaker Playback Switch");
+               break;
+       }
+}
+
 /* for hda_fixup_thinkpad_acpi() */
 #include "thinkpad_helper.c"
 
@@ -6720,91 +6774,30 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
        }
 }
 
-#ifdef CONFIG_ACPI
 static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
 {
        struct hda_codec *cdc = data;
        struct alc_spec *spec = cdc->spec;
-       int i;
 
        codec_info(cdc, "ACPI Notification %d\n", event);
 
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
-               if (spec->comps[i].dev && spec->comps[i].acpi_notify)
-                       spec->comps[i].acpi_notify(acpi_device_handle(spec->comps[i].adev), event,
-                                                  spec->comps[i].dev);
-       }
-}
-
-static int comp_bind_acpi(struct device *dev)
-{
-       struct hda_codec *cdc = dev_to_hda_codec(dev);
-       struct alc_spec *spec = cdc->spec;
-       bool support_notifications = false;
-       struct acpi_device *adev;
-       int ret;
-       int i;
-
-       adev = spec->comps[0].adev;
-       if (!acpi_device_handle(adev))
-               return 0;
-
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++)
-               support_notifications = support_notifications ||
-                       spec->comps[i].acpi_notifications_supported;
-
-       if (support_notifications) {
-               ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
-                                               comp_acpi_device_notify, cdc);
-               if (ret < 0) {
-                       codec_warn(cdc, "Failed to install notify handler: %d\n", ret);
-                       return 0;
-               }
-
-               codec_dbg(cdc, "Notify handler installed\n");
-       }
-
-       return 0;
-}
-
-static void comp_unbind_acpi(struct device *dev)
-{
-       struct hda_codec *cdc = dev_to_hda_codec(dev);
-       struct alc_spec *spec = cdc->spec;
-       struct acpi_device *adev;
-       int ret;
-
-       adev = spec->comps[0].adev;
-       if (!acpi_device_handle(adev))
-               return;
-
-       ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
-                                        comp_acpi_device_notify);
-       if (ret < 0)
-               codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret);
-}
-#else
-static int comp_bind_acpi(struct device *dev)
-{
-       return 0;
+       hda_component_acpi_device_notify(spec->comps, ARRAY_SIZE(spec->comps),
+                                        handle, event, data);
 }
 
-static void comp_unbind_acpi(struct device *dev)
-{
-}
-#endif
-
 static int comp_bind(struct device *dev)
 {
        struct hda_codec *cdc = dev_to_hda_codec(dev);
        struct alc_spec *spec = cdc->spec;
        int ret;
 
-       ret = component_bind_all(dev, spec->comps);
+       ret = hda_component_manager_bind(cdc, spec->comps);
        if (ret)
                return ret;
 
-       return comp_bind_acpi(dev);
+       return hda_component_manager_bind_acpi_notifications(cdc,
+                                                            spec->comps, ARRAY_SIZE(spec->comps),
+                                                            comp_acpi_device_notify, cdc);
 }
 
 static void comp_unbind(struct device *dev)
@@ -6812,8 +6805,8 @@ static void comp_unbind(struct device *dev)
        struct hda_codec *cdc = dev_to_hda_codec(dev);
        struct alc_spec *spec = cdc->spec;
 
-       comp_unbind_acpi(dev);
-       component_unbind_all(dev, spec->comps);
+       hda_component_manager_unbind_acpi_notifications(cdc, spec->comps, comp_acpi_device_notify);
+       hda_component_manager_unbind(cdc, spec->comps);
 }
 
 static const struct component_master_ops comp_master_ops = {
@@ -6825,179 +6818,87 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_
                                       struct snd_pcm_substream *sub, int action)
 {
        struct alc_spec *spec = cdc->spec;
-       int i;
-
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
-               if (spec->comps[i].dev && spec->comps[i].pre_playback_hook)
-                       spec->comps[i].pre_playback_hook(spec->comps[i].dev, action);
-       }
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
-               if (spec->comps[i].dev && spec->comps[i].playback_hook)
-                       spec->comps[i].playback_hook(spec->comps[i].dev, action);
-       }
-       for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
-               if (spec->comps[i].dev && spec->comps[i].post_playback_hook)
-                       spec->comps[i].post_playback_hook(spec->comps[i].dev, action);
-       }
-}
-
-struct scodec_dev_name {
-       const char *bus;
-       const char *hid;
-       int index;
-};
-
-/* match the device name in a slightly relaxed manner */
-static int comp_match_cs35l41_dev_name(struct device *dev, void *data)
-{
-       struct scodec_dev_name *p = data;
-       const char *d = dev_name(dev);
-       int n = strlen(p->bus);
-       char tmp[32];
-
-       /* check the bus name */
-       if (strncmp(d, p->bus, n))
-               return 0;
-       /* skip the bus number */
-       if (isdigit(d[n]))
-               n++;
-       /* the rest must be exact matching */
-       snprintf(tmp, sizeof(tmp), "-%s:00-cs35l41-hda.%d", p->hid, p->index);
-       return !strcmp(d + n, tmp);
-}
-
-static int comp_match_tas2781_dev_name(struct device *dev,
-       void *data)
-{
-       struct scodec_dev_name *p = data;
-       const char *d = dev_name(dev);
-       int n = strlen(p->bus);
-       char tmp[32];
-
-       /* check the bus name */
-       if (strncmp(d, p->bus, n))
-               return 0;
-       /* skip the bus number */
-       if (isdigit(d[n]))
-               n++;
-       /* the rest must be exact matching */
-       snprintf(tmp, sizeof(tmp), "-%s:00", p->hid);
-
-       return !strcmp(d + n, tmp);
-}
-
-static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
-                                 const char *hid, int count)
-{
-       struct device *dev = hda_codec_dev(cdc);
-       struct alc_spec *spec = cdc->spec;
-       struct scodec_dev_name *rec;
-       int ret, i;
 
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               for (i = 0; i < count; i++) {
-                       rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL);
-                       if (!rec)
-                               return;
-                       rec->bus = bus;
-                       rec->hid = hid;
-                       rec->index = i;
-                       spec->comps[i].codec = cdc;
-                       component_match_add(dev, &spec->match,
-                                           comp_match_cs35l41_dev_name, rec);
-               }
-               ret = component_master_add_with_match(dev, &comp_master_ops, spec->match);
-               if (ret)
-                       codec_err(cdc, "Fail to register component aggregator %d\n", ret);
-               else
-                       spec->gen.pcm_playback_hook = comp_generic_playback_hook;
-               break;
-       case HDA_FIXUP_ACT_FREE:
-               component_master_del(dev, &comp_master_ops);
-               break;
-       }
+       hda_component_manager_playback_hook(spec->comps, ARRAY_SIZE(spec->comps), action);
 }
 
-static void tas2781_generic_fixup(struct hda_codec *cdc, int action,
-       const char *bus, const char *hid)
+static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
+                              const char *hid, const char *match_str, int count)
 {
-       struct device *dev = hda_codec_dev(cdc);
        struct alc_spec *spec = cdc->spec;
-       struct scodec_dev_name *rec;
        int ret;
 
        switch (action) {
        case HDA_FIXUP_ACT_PRE_PROBE:
-               rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL);
-               if (!rec)
-                       return;
-               rec->bus = bus;
-               rec->hid = hid;
-               rec->index = 0;
-               spec->comps[0].codec = cdc;
-               component_match_add(dev, &spec->match,
-                       comp_match_tas2781_dev_name, rec);
-               ret = component_master_add_with_match(dev, &comp_master_ops,
-                       spec->match);
+               ret = hda_component_manager_init(cdc, spec->comps, count, bus, hid,
+                                                match_str, &comp_master_ops);
                if (ret)
-                       codec_err(cdc,
-                               "Fail to register component aggregator %d\n",
-                               ret);
-               else
-                       spec->gen.pcm_playback_hook =
-                               comp_generic_playback_hook;
+                       return;
+
+               spec->gen.pcm_playback_hook = comp_generic_playback_hook;
                break;
        case HDA_FIXUP_ACT_FREE:
-               component_master_del(dev, &comp_master_ops);
+               hda_component_manager_free(cdc, &comp_master_ops);
                break;
        }
 }
 
 static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
 {
-       cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2);
+       comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
 }
 
 static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
 {
-       cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 4);
+       comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
 }
 
 static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
 {
-       cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 2);
+       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
 }
 
 static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action)
 {
-       cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 4);
+       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
 }
 
 static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
                                                 int action)
 {
-       cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0100", 2);
+       comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 2);
 }
 
 static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
                                                 int action)
 {
-       cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2);
+       comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void cs35l56_fixup_spi_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(cdc, action, "spi", "CSC3556", "-%s:00-cs35l56-hda.%d", 4);
 }
 
 static void tas2781_fixup_i2c(struct hda_codec *cdc,
        const struct hda_fixup *fix, int action)
 {
-        tas2781_generic_fixup(cdc, action, "i2c", "TIAS2781");
+       comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
 }
 
 static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
        const struct hda_fixup *fix, int action)
 {
-        tas2781_generic_fixup(cdc, action, "i2c", "INT8866");
+       comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1);
+}
+
+static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
+       const struct hda_fixup *fix, int action)
+{
+       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
 }
 
+
 /* for alc295_fixup_hp_top_speakers */
 #include "hp_x360_helper.c"
 
@@ -7064,6 +6965,25 @@ static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
        }
 }
 
+static void alc256_decrease_headphone_amp_val(struct hda_codec *codec,
+                                             const struct hda_fixup *fix, int action)
+{
+       u32 caps;
+       u8 nsteps, offs;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       caps = query_amp_caps(codec, 0x3, HDA_OUTPUT);
+       nsteps = ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) - 10;
+       offs = ((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT) - 10;
+       caps &= ~AC_AMPCAP_NUM_STEPS & ~AC_AMPCAP_OFFSET;
+       caps |= (nsteps << AC_AMPCAP_NUM_STEPS_SHIFT) | (offs << AC_AMPCAP_OFFSET_SHIFT);
+
+       if (snd_hda_override_amp_caps(codec, 0x3, HDA_OUTPUT, caps))
+               codec_warn(codec, "failed to override amp caps for NID 0x3\n");
+}
+
 static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec,
                                                  const struct hda_fixup *fix,
                                                  int action)
@@ -7204,6 +7124,38 @@ static void alc_fixup_headset_mic(struct hda_codec *codec,
        }
 }
 
+static void alc245_fixup_hp_spectre_x360_eu0xxx(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       /*
+        * The Pin Complex 0x14 for the treble speakers is wrongly reported as
+        * unconnected.
+        * The Pin Complex 0x17 for the bass speakers has the lowest association
+        * and sequence values so shift it up a bit to squeeze 0x14 in.
+        */
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x14, 0x90170110 }, // top/treble
+               { 0x17, 0x90170111 }, // bottom/bass
+               { }
+       };
+
+       /*
+        * Force DAC 0x02 for the bass speakers 0x17.
+        */
+       static const hda_nid_t conn[] = { 0x02 };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               break;
+       }
+
+       cs35l41_fixup_i2c_two(codec, fix, action);
+       alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc245_fixup_hp_gpio_led(codec, fix, action);
+}
+
 
 enum {
        ALC269_FIXUP_GPIO2,
@@ -7297,6 +7249,7 @@ enum {
        ALC280_FIXUP_HP_9480M,
        ALC245_FIXUP_HP_X360_AMP,
        ALC285_FIXUP_HP_SPECTRE_X360_EB1,
+       ALC285_FIXUP_HP_ENVY_X360,
        ALC288_FIXUP_DELL_HEADSET_MODE,
        ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
        ALC288_FIXUP_DELL_XPS_13,
@@ -7466,6 +7419,7 @@ enum {
        ALC287_FIXUP_LEGION_16ITHG6,
        ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
        ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
+       ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN,
        ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS,
        ALC236_FIXUP_DELL_DUAL_CODECS,
        ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
@@ -7478,6 +7432,10 @@ enum {
        ALC2XX_FIXUP_HEADSET_MIC,
        ALC289_FIXUP_DELL_CS35L41_SPI_2,
        ALC294_FIXUP_CS35L41_I2C_2,
+       ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED,
+       ALC256_FIXUP_ACER_SFG16_MICMUTE_LED,
+       ALC256_FIXUP_HEADPHONE_AMP_VOL,
+       ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX,
 };
 
 /* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -9273,6 +9231,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc285_fixup_hp_spectre_x360_eb1
        },
+       [ALC285_FIXUP_HP_ENVY_X360] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_envy_x360,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_GPIO_AMP_INIT,
+       },
        [ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc285_fixup_ideapad_s740_coef,
@@ -9589,6 +9553,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
        },
+       [ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin,
+               .chained = true,
+               .chain_id = ALC287_FIXUP_CS35L41_I2C_2,
+       },
        [ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc295_fixup_dell_inspiron_top_speakers,
@@ -9655,6 +9625,24 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cs35l41_fixup_i2c_two,
        },
+       [ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l56_fixup_spi_four,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_GPIO_LED,
+       },
+       [ALC256_FIXUP_ACER_SFG16_MICMUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_fixup_acer_sfg16_micmute_led,
+       },
+       [ALC256_FIXUP_HEADPHONE_AMP_VOL] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_decrease_headphone_amp_val,
+       },
+       [ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_spectre_x360_eu0xxx,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -9698,6 +9686,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
        SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
        SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
@@ -9861,6 +9850,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
        SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360),
        SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360),
        SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
@@ -9947,9 +9937,22 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
        SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8a28, "HP Envy 13", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a29, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2b, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2c, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
+       SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
@@ -9959,8 +9962,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ad8, "HP 800 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x8b3a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8b3f, "HP mt440 Mobile Thin Client U91", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
@@ -9988,11 +9993,35 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be0, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be1, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be2, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be3, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be5, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be6, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be7, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+       SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c4f, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c50, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c51, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c66, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c67, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c68, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c6a, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
@@ -10006,6 +10035,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
@@ -10127,6 +10158,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
@@ -10145,12 +10177,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x152d, 0x1082, "Quanta NL3", ALC269_FIXUP_LIFEBOOK),
+       SND_PCI_QUIRK(0x1558, 0x0353, "Clevo V35[05]SN[CDE]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1323, "Clevo N130ZU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1325, "Clevo N15[01][CW]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1401, "Clevo L140[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1403, "Clevo N140CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x2624, "Clevo L240TU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -10320,6 +10354,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x38c3, "Y980 DUAL", ALC287_FIXUP_TAS2781_I2C),
        SND_PCI_QUIRK(0x17aa, 0x38cb, "Y790 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
        SND_PCI_QUIRK(0x17aa, 0x38cd, "Y790 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38d2, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x38d7, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN),
        SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
@@ -10347,6 +10383,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x9e56, "Lenovo ZhaoYang CF4620Z", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
        SND_PCI_QUIRK(0x1849, 0xa233, "Positivo Master C6300", ALC269_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1854, 0x0440, "LG CQ6", ALC256_FIXUP_HEADPHONE_AMP_VOL),
+       SND_PCI_QUIRK(0x1854, 0x0441, "LG CQ6 AIO", ALC256_FIXUP_HEADPHONE_AMP_VOL),
        SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
        SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
@@ -10559,6 +10597,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"},
        {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"},
        {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"},
+       {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"},
        {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
        {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"},
        {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"},
@@ -12674,6 +12713,7 @@ MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek HD-audio codec");
+MODULE_IMPORT_NS(SND_HDA_SCODEC_COMPONENT);
 
 static struct hda_codec_driver realtek_driver = {
        .id = snd_hda_id_realtek,
index 4c9a788c350129bb32f0adf1590645e1401158e8..4475cea8e9f70382113c3e6f496eebc854c92b40 100644 (file)
@@ -148,11 +148,13 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
                pm_runtime_get_sync(dev);
                mutex_lock(&tas_hda->priv->codec_lock);
                tasdevice_tuning_switch(tas_hda->priv, 0);
+               tas_hda->priv->playback_started = true;
                mutex_unlock(&tas_hda->priv->codec_lock);
                break;
        case HDA_GEN_PCM_ACT_CLOSE:
                mutex_lock(&tas_hda->priv->codec_lock);
                tasdevice_tuning_switch(tas_hda->priv, 1);
+               tas_hda->priv->playback_started = false;
                mutex_unlock(&tas_hda->priv->codec_lock);
 
                pm_runtime_mark_last_busy(dev);
@@ -654,6 +656,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
        tasdevice_save_calibration(tas_priv);
 
        tasdevice_tuning_switch(tas_hda->priv, 0);
+       tas_hda->priv->playback_started = true;
 
 out:
        mutex_unlock(&tas_hda->priv->codec_lock);
@@ -793,11 +796,8 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
        pm_runtime_use_autosuspend(tas_hda->dev);
        pm_runtime_mark_last_busy(tas_hda->dev);
        pm_runtime_set_active(tas_hda->dev);
-       pm_runtime_get_noresume(tas_hda->dev);
        pm_runtime_enable(tas_hda->dev);
 
-       pm_runtime_put_autosuspend(tas_hda->dev);
-
        tas2781_reset(tas_hda->priv);
 
        ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops);
@@ -820,23 +820,19 @@ static void tas2781_hda_i2c_remove(struct i2c_client *clt)
 static int tas2781_runtime_suspend(struct device *dev)
 {
        struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       int i;
 
        dev_dbg(tas_hda->dev, "Runtime Suspend\n");
 
        mutex_lock(&tas_hda->priv->codec_lock);
 
+       /* The driver powers up the amplifiers at module load time.
+        * Stop the playback if it's unused.
+        */
        if (tas_hda->priv->playback_started) {
                tasdevice_tuning_switch(tas_hda->priv, 1);
                tas_hda->priv->playback_started = false;
        }
 
-       for (i = 0; i < tas_hda->priv->ndev; i++) {
-               tas_hda->priv->tasdevice[i].cur_book = -1;
-               tas_hda->priv->tasdevice[i].cur_prog = -1;
-               tas_hda->priv->tasdevice[i].cur_conf = -1;
-       }
-
        mutex_unlock(&tas_hda->priv->codec_lock);
 
        return 0;
@@ -865,16 +861,16 @@ static int tas2781_runtime_resume(struct device *dev)
 static int tas2781_system_suspend(struct device *dev)
 {
        struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       int ret;
 
        dev_dbg(tas_hda->priv->dev, "System Suspend\n");
 
-       ret = pm_runtime_force_suspend(dev);
-       if (ret)
-               return ret;
+       mutex_lock(&tas_hda->priv->codec_lock);
 
        /* Shutdown chip before system suspend */
-       tasdevice_tuning_switch(tas_hda->priv, 1);
+       if (tas_hda->priv->playback_started)
+               tasdevice_tuning_switch(tas_hda->priv, 1);
+
+       mutex_unlock(&tas_hda->priv->codec_lock);
 
        /*
         * Reset GPIO may be shared, so cannot reset here.
@@ -886,13 +882,9 @@ static int tas2781_system_suspend(struct device *dev)
 static int tas2781_system_resume(struct device *dev)
 {
        struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       int i, ret;
-
-       dev_info(tas_hda->priv->dev, "System Resume\n");
+       int i;
 
-       ret = pm_runtime_force_resume(dev);
-       if (ret)
-               return ret;
+       dev_dbg(tas_hda->priv->dev, "System Resume\n");
 
        mutex_lock(&tas_hda->priv->codec_lock);
 
@@ -908,6 +900,10 @@ static int tas2781_system_resume(struct device *dev)
         * calibrated data inside algo.
         */
        tasdevice_apply_calibration(tas_hda->priv);
+
+       if (tas_hda->priv->playback_started)
+               tasdevice_tuning_switch(tas_hda->priv, 0);
+
        mutex_unlock(&tas_hda->priv->codec_lock);
 
        return 0;
index ae285c0a629c82a518af20812d681526b4e61a73..dae3e15ba534de63e6071f3b3831941687bd1fc3 100644 (file)
@@ -2555,7 +2555,6 @@ static void snd_intel8x0_free(struct snd_card *card)
                free_irq(chip->irq, chip);
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -2628,11 +2627,7 @@ static int intel8x0_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);
-#define INTEL8X0_PM_OPS        &intel8x0_pm
-#else
-#define INTEL8X0_PM_OPS        NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);
 
 #define INTEL8X0_TESTBUF_SIZE  32768   /* enough large for one shot */
 
@@ -3200,7 +3195,7 @@ static struct pci_driver intel8x0_driver = {
        .id_table = snd_intel8x0_ids,
        .probe = snd_intel8x0_probe,
        .driver = {
-               .pm = INTEL8X0_PM_OPS,
+               .pm = &intel8x0_pm,
        },
 };
 
index 653ecca782382028c520dbc6e32a0f09ca49cf2c..3d6f5b3cc73e173299f2f17d9ac3ac25cb08f4c3 100644 (file)
@@ -965,7 +965,6 @@ static void snd_intel8x0m_free(struct snd_card *card)
                free_irq(chip->irq, chip);
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1006,11 +1005,7 @@ static int intel8x0m_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume);
-#define INTEL8X0M_PM_OPS       &intel8x0m_pm
-#else
-#define INTEL8X0M_PM_OPS       NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume);
 
 static void snd_intel8x0m_proc_read(struct snd_info_entry * entry,
                                   struct snd_info_buffer *buffer)
@@ -1236,7 +1231,7 @@ static struct pci_driver intel8x0m_driver = {
        .id_table = snd_intel8x0m_ids,
        .probe = snd_intel8x0m_probe,
        .driver = {
-               .pm = INTEL8X0M_PM_OPS,
+               .pm = &intel8x0m_pm,
        },
 };
 
index 305cbd24a3918eaddb7c9ff552fa5754d41d3c34..f4d211970d7ec98bb626f1187edc8842c44c13ae 100644 (file)
@@ -769,9 +769,7 @@ struct snd_m3 {
 
        unsigned int in_suspend;
 
-#ifdef CONFIG_PM_SLEEP
        u16 *suspend_mem;
-#endif
 
        const struct firmware *assp_kernel_image;
        const struct firmware *assp_minisrc_image;
@@ -2354,9 +2352,7 @@ static void snd_m3_free(struct snd_card *card)
                outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
        }
 
-#ifdef CONFIG_PM_SLEEP
        vfree(chip->suspend_mem);
-#endif
        release_firmware(chip->assp_kernel_image);
        release_firmware(chip->assp_minisrc_image);
 }
@@ -2365,7 +2361,6 @@ static void snd_m3_free(struct snd_card *card)
 /*
  * APM support
  */
-#ifdef CONFIG_PM_SLEEP
 static int m3_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
@@ -2439,11 +2434,7 @@ static int m3_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);
-#define M3_PM_OPS      &m3_pm
-#else
-#define M3_PM_OPS      NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);
 
 #ifdef CONFIG_SND_MAESTRO3_INPUT
 static int snd_m3_input_register(struct snd_m3 *chip)
@@ -2587,14 +2578,14 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
        chip->irq = pci->irq;
        card->sync_irq = chip->irq;
 
-#ifdef CONFIG_PM_SLEEP
-       chip->suspend_mem =
-               vmalloc(array_size(sizeof(u16),
-                                  REV_B_CODE_MEMORY_LENGTH +
-                                       REV_B_DATA_MEMORY_LENGTH));
-       if (chip->suspend_mem == NULL)
-               dev_warn(card->dev, "can't allocate apm buffer\n");
-#endif
+       if (IS_ENABLED(CONFIG_PM_SLEEP)) {
+               chip->suspend_mem =
+                       vmalloc(array_size(sizeof(u16),
+                                          REV_B_CODE_MEMORY_LENGTH +
+                                          REV_B_DATA_MEMORY_LENGTH));
+               if (!chip->suspend_mem)
+                       dev_warn(card->dev, "can't allocate apm buffer\n");
+       }
 
        err = snd_m3_mixer(chip);
        if (err < 0)
@@ -2706,7 +2697,7 @@ static struct pci_driver m3_driver = {
        .id_table = snd_m3_ids,
        .probe = snd_m3_probe,
        .driver = {
-               .pm = M3_PM_OPS,
+               .pm = &m3_pm,
        },
 };
        
index 34f90829e65692f3aa9779b4fe861048b39ff49a..11ba7d4eac2a4e02111ef4f0775f0a2449056c84 100644 (file)
@@ -1356,7 +1356,6 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * APM event handler, so the card is properly reinitialized after a power
  * event.
@@ -1400,11 +1399,7 @@ static int nm256_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume);
-#define NM256_PM_OPS   &nm256_pm
-#else
-#define NM256_PM_OPS   NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume);
 
 static void snd_nm256_free(struct snd_card *card)
 {
@@ -1660,7 +1655,7 @@ static struct pci_driver nm256_driver = {
        .id_table = snd_nm256_ids,
        .probe = snd_nm256_probe,
        .driver = {
-               .pm = NM256_PM_OPS,
+               .pm = &nm256_pm,
        },
 };
 
index 9dee0345f22cf1e550d38f1c3b3c7918e2f116c5..7e80686fb41a33ea09a71f4d95db612d89d89d50 100644 (file)
@@ -448,9 +448,7 @@ struct snd_riptide {
 
        unsigned long received_irqs;
        unsigned long handled_irqs;
-#ifdef CONFIG_PM_SLEEP
        int in_suspend;
-#endif
 };
 
 struct sgd {                   /* scatter gather desriptor */
@@ -1142,7 +1140,6 @@ static irqreturn_t riptide_handleirq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int riptide_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
@@ -1166,11 +1163,7 @@ static int riptide_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume);
-#define RIPTIDE_PM_OPS &riptide_pm
-#else
-#define RIPTIDE_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume);
 
 static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
 {
@@ -2135,7 +2128,7 @@ static struct pci_driver driver = {
        .id_table = snd_riptide_ids,
        .probe = snd_card_riptide_probe,
        .driver = {
-               .pm = RIPTIDE_PM_OPS,
+               .pm = &riptide_pm,
        },
 };
 
index 6b5ffb18197b0d002ea9a4380df438f1ba86843e..d50ad25574adac15b68787dba9ac9fb5f1496538 100644 (file)
@@ -220,12 +220,10 @@ struct rme96 {
 
        u8 rev; /* card revision number */
 
-#ifdef CONFIG_PM_SLEEP
        u32 playback_pointer;
        u32 capture_pointer;
        void *playback_suspend_buffer;
        void *capture_suspend_buffer;
-#endif
 
        struct snd_pcm_substream *playback_substream;
        struct snd_pcm_substream *capture_substream;
@@ -1543,10 +1541,8 @@ snd_rme96_free(struct rme96 *rme96)
                rme96->areg &= ~RME96_AR_DAC_EN;
                writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
        }
-#ifdef CONFIG_PM_SLEEP
        vfree(rme96->playback_suspend_buffer);
        vfree(rme96->capture_suspend_buffer);
-#endif
 }
 
 static void
@@ -2329,8 +2325,6 @@ snd_rme96_create_switches(struct snd_card *card,
  * Card initialisation
  */
 
-#ifdef CONFIG_PM_SLEEP
-
 static int rme96_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
@@ -2392,11 +2386,7 @@ static int rme96_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume);
-#define RME96_PM_OPS   &rme96_pm
-#else
-#define RME96_PM_OPS   NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume);
 
 static void snd_rme96_card_free(struct snd_card *card)
 {
@@ -2432,14 +2422,14 @@ __snd_rme96_probe(struct pci_dev *pci,
        if (err)
                return err;
        
-#ifdef CONFIG_PM_SLEEP
-       rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
-       if (!rme96->playback_suspend_buffer)
-               return -ENOMEM;
-       rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
-       if (!rme96->capture_suspend_buffer)
-               return -ENOMEM;
-#endif
+       if (IS_ENABLED(CONFIG_PM_SLEEP)) {
+               rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
+               if (!rme96->playback_suspend_buffer)
+                       return -ENOMEM;
+               rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
+               if (!rme96->capture_suspend_buffer)
+                       return -ENOMEM;
+       }
 
        strcpy(card->driver, "Digi96");
        switch (rme96->pci->device) {
@@ -2483,7 +2473,7 @@ static struct pci_driver rme96_driver = {
        .id_table = snd_rme96_ids,
        .probe = snd_rme96_probe,
        .driver = {
-               .pm = RME96_PM_OPS,
+               .pm = &rme96_pm,
        },
 };
 
index fabe393607f8fa2862db6b73e5247d7bd1f63ccf..53206beb2cb50d704c54029bb9d5fc52ae16e653 100644 (file)
@@ -90,11 +90,7 @@ struct voice {
  * we're not doing power management, we still need to allocate a page
  * for the silence buffer.
  */
-#ifdef CONFIG_PM_SLEEP
 #define SIS_SUSPEND_PAGES      4
-#else
-#define SIS_SUSPEND_PAGES      1
-#endif
 
 struct sis7019 {
        unsigned long ioport;
@@ -1152,7 +1148,6 @@ static int sis_chip_init(struct sis7019 *sis)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int sis_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
@@ -1231,11 +1226,7 @@ error:
        return -EIO;
 }
 
-static SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume);
-#define SIS_PM_OPS     &sis_pm
-#else
-#define SIS_PM_OPS     NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume);
 
 static int sis_alloc_suspend(struct sis7019 *sis)
 {
@@ -1397,7 +1388,7 @@ static struct pci_driver sis7019_driver = {
        .id_table = snd_sis7019_ids,
        .probe = snd_sis7019_probe,
        .driver = {
-               .pm = SIS_PM_OPS,
+               .pm = &sis_pm,
        },
 };
 
index d8666ff7bdfae02e8278f7e698fb7927d479c3b7..89838b4fb118a30f51924eca79568fbd4e1d61eb 100644 (file)
@@ -347,13 +347,11 @@ struct via82xx {
 
        unsigned char old_legacy;
        unsigned char old_legacy_cfg;
-#ifdef CONFIG_PM_SLEEP
        unsigned char legacy_saved;
        unsigned char legacy_cfg_saved;
        unsigned char spdif_ctrl_saved;
        unsigned char capture_src_saved[2];
        unsigned int mpu_port_saved;
-#endif
 
        unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */
        unsigned char playback_volume_c[2]; /* for VIA8233/C/8235; default = 0 */
@@ -2031,9 +2029,7 @@ static int snd_via686_init_misc(struct via82xx *chip)
                if (mpu_port >= 0x200) {        /* force MIDI */
                        mpu_port &= 0xfffc;
                        pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01);
-#ifdef CONFIG_PM_SLEEP
                        chip->mpu_port_saved = mpu_port;
-#endif
                } else {
                        mpu_port = pci_resource_start(chip->pci, 2);
                }
@@ -2085,10 +2081,8 @@ static int snd_via686_init_misc(struct via82xx *chip)
 
        snd_via686_create_gameport(chip, &legacy);
 
-#ifdef CONFIG_PM_SLEEP
        chip->legacy_saved = legacy;
        chip->legacy_cfg_saved = legacy_cfg;
-#endif
 
        return 0;
 }
@@ -2234,7 +2228,6 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -2287,11 +2280,7 @@ static int snd_via82xx_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
-#define SND_VIA82XX_PM_OPS     &snd_via82xx_pm
-#else
-#define SND_VIA82XX_PM_OPS     NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
 
 static void snd_via82xx_free(struct snd_card *card)
 {
@@ -2576,7 +2565,7 @@ static struct pci_driver via82xx_driver = {
        .id_table = snd_via82xx_ids,
        .probe = snd_via82xx_probe,
        .driver = {
-               .pm = SND_VIA82XX_PM_OPS,
+               .pm = &snd_via82xx_pm,
        },
 };
 
index ca7f024bf8ec6efe5387d205512120cdbc8872aa..a0a49b8d151160482fef70a21e1b32e37575116b 100644 (file)
@@ -1008,7 +1008,6 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1042,11 +1041,7 @@ static int snd_via82xx_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
-#define SND_VIA82XX_PM_OPS     &snd_via82xx_pm
-#else
-#define SND_VIA82XX_PM_OPS     NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
 
 static void snd_via82xx_free(struct snd_card *card)
 {
@@ -1168,7 +1163,7 @@ static struct pci_driver via82xx_modem_driver = {
        .id_table = snd_via82xx_modem_ids,
        .probe = snd_via82xx_probe,
        .driver = {
-               .pm = SND_VIA82XX_PM_OPS,
+               .pm = &snd_via82xx_pm,
        },
 };
 
index eaa4c706f3a2f5cb1b560261ce629cf97dd88d18..14a5f86019aad47390ee8f3962a596296dfbf437 100644 (file)
@@ -386,7 +386,7 @@ static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral,
        dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n",
                __func__, sclk, params->col, params->row);
 
-       if (cs35l56->base.rev < 0xb0)
+       if ((cs35l56->base.type == 0x56) && (cs35l56->base.rev < 0xb0))
                return cs35l56_a1_kick_divider(cs35l56, peripheral);
 
        return 0;
@@ -563,6 +563,7 @@ static const struct dev_pm_ops cs35l56_sdw_pm = {
 
 static const struct sdw_device_id cs35l56_sdw_id[] = {
        SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0),
+       SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0),
        {},
 };
 MODULE_DEVICE_TABLE(sdw, cs35l56_sdw_id);
index f3670bf85a9504e2885186872c9c395ba0636355..08cac58e3ab2223c82b4da10314f04b2f055b5b6 100644 (file)
@@ -776,13 +776,17 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
        devid &= CS35L56_DEVID_MASK;
 
        switch (devid) {
+       case 0x35A54:
        case 0x35A56:
+       case 0x35A57:
                break;
        default:
                dev_err(cs35l56_base->dev, "Unknown device %x\n", devid);
                return ret;
        }
 
+       cs35l56_base->type = devid & 0xFF;
+
        ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
        if (ret) {
                dev_err(cs35l56_base->dev, "Get Secure status failed\n");
@@ -803,8 +807,8 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
        if (ret)
                return ret;
 
-       dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n",
-                cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid,
+       dev_info(cs35l56_base->dev, "Cirrus Logic CS35L%02X%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n",
+                cs35l56_base->type, cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid,
                 fw_ver >> 16, (fw_ver >> 8) & 0xff, fw_ver & 0xff, !fw_missing);
 
        /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
index 8a0ca08127725525b033f09d4a1971f5b288a29e..8d2f021fb362812a73d07d10565a23d2b77f6a38 100644 (file)
@@ -1004,6 +1004,10 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
                return -ENODEV;
        }
 
+       cs35l56->dsp.part = kasprintf(GFP_KERNEL, "cs35l%02x", cs35l56->base.type);
+       if (!cs35l56->dsp.part)
+               return -ENOMEM;
+
        cs35l56->component = component;
        wm_adsp2_component_probe(&cs35l56->dsp, component);
 
@@ -1034,6 +1038,9 @@ static void cs35l56_component_remove(struct snd_soc_component *component)
 
        wm_adsp2_component_remove(&cs35l56->dsp, component);
 
+       kfree(cs35l56->dsp.part);
+       cs35l56->dsp.part = NULL;
+
        kfree(cs35l56->dsp.fwf_name);
        cs35l56->dsp.fwf_name = NULL;
 
@@ -1253,7 +1260,12 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
 
        dsp = &cs35l56->dsp;
        cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp);
-       dsp->part = "cs35l56";
+
+       /*
+        * dsp->part is filled in later as it is based on the DEVID. In a
+        * SoundWire system that cannot be read until enumeration has occurred
+        * and the device has attached.
+        */
        dsp->fw = 12;
        dsp->wmfw_optional = true;
 
index d2117e36ddd107704e7685d783e777eaf93b6b4b..5a58723dc0e96b8309b60a8b71ef0f30b2c7ea46 100644 (file)
@@ -198,19 +198,19 @@ static int hda_codec_probe(struct snd_soc_component *component)
        ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec,
                                       false);
        if (ret < 0) {
-               dev_err(&hdev->dev, "create hda codec failed: %d\n", ret);
+               dev_err(&hdev->dev, "codec create failed: %d\n", ret);
                goto device_new_err;
        }
 
        ret = snd_hda_codec_set_name(codec, codec->preset->name);
        if (ret < 0) {
-               dev_err(&hdev->dev, "name failed %s\n", codec->preset->name);
+               dev_err(&hdev->dev, "set name: %s failed: %d\n", codec->preset->name, ret);
                goto err;
        }
 
        ret = snd_hdac_regmap_init(&codec->core);
        if (ret < 0) {
-               dev_err(&hdev->dev, "regmap init failed\n");
+               dev_err(&hdev->dev, "regmap init failed: %d\n", ret);
                goto err;
        }
 
@@ -223,13 +223,13 @@ static int hda_codec_probe(struct snd_soc_component *component)
 
        ret = patch(codec);
        if (ret < 0) {
-               dev_err(&hdev->dev, "patch failed %d\n", ret);
+               dev_err(&hdev->dev, "codec init failed: %d\n", ret);
                goto err;
        }
 
        ret = snd_hda_codec_parse_pcms(codec);
        if (ret < 0) {
-               dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
+               dev_err(&hdev->dev, "unable to map pcms to dai: %d\n", ret);
                goto parse_pcms_err;
        }
 
@@ -350,6 +350,11 @@ static int hda_hdev_attach(struct hdac_device *hdev)
        struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
        struct snd_soc_component_driver *comp_drv;
 
+       if (hda_codec_is_display(codec) && !hdev->bus->audio_component) {
+               dev_dbg(&hdev->dev, "no i915, skip registration for 0x%08x\n", hdev->vendor_id);
+               return -ENODEV;
+       }
+
        comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL);
        if (!comp_drv)
                return -ENOMEM;
index 5e9cae1f47f55fb6e2c0a599dfb2cdef3d29260b..d7f8940099cec6510c1179b7045134243767625d 100644 (file)
@@ -149,7 +149,7 @@ static int probe_codec(struct hdac_bus *bus, int addr)
        /* configure effectively creates new ASoC component */
        ret = snd_hda_codec_configure(codec);
        if (ret < 0) {
-               dev_err(bus->dev, "failed to config codec %d\n", ret);
+               dev_warn(bus->dev, "failed to config codec #%d: %d\n", addr, ret);
                return ret;
        }
 
@@ -158,15 +158,16 @@ static int probe_codec(struct hdac_bus *bus, int addr)
 
 static void avs_hdac_bus_probe_codecs(struct hdac_bus *bus)
 {
-       int c;
+       int ret, c;
 
        /* First try to probe all given codec slots */
        for (c = 0; c < HDA_MAX_CODECS; c++) {
                if (!(bus->codec_mask & BIT(c)))
                        continue;
 
-               if (!probe_codec(bus, c))
-                       /* success, continue probing */
+               ret = probe_codec(bus, c);
+               /* Ignore codecs with no supporting driver. */
+               if (!ret || ret == -ENODEV)
                        continue;
 
                /*
index e73bd62c033c5330313cb9f8f7fb039eb02e9ca6..80e0ea0ec9fb3af9fd29e4d70badfbfe3223c961 100644 (file)
@@ -271,7 +271,6 @@ static void pxa2xx_ac97_dev_remove(struct platform_device *pdev)
        pxa2xx_ac97_hw_remove(pdev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int pxa2xx_ac97_dev_suspend(struct device *dev)
 {
        return pxa2xx_ac97_hw_suspend();
@@ -282,18 +281,15 @@ static int pxa2xx_ac97_dev_resume(struct device *dev)
        return pxa2xx_ac97_hw_resume();
 }
 
-static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops,
                pxa2xx_ac97_dev_suspend, pxa2xx_ac97_dev_resume);
-#endif
 
 static struct platform_driver pxa2xx_ac97_driver = {
        .probe          = pxa2xx_ac97_dev_probe,
        .remove_new     = pxa2xx_ac97_dev_remove,
        .driver         = {
                .name   = "pxa2xx-ac97",
-#ifdef CONFIG_PM_SLEEP
                .pm     = &pxa2xx_ac97_pm_ops,
-#endif
                .of_match_table = of_match_ptr(pxa2xx_ac97_dt_ids),
        },
 };
index 1e8765d75d8f8dcac08ad2a5443695449293b3bb..5648d744aa79ff4a92e0bfe5b50fe60d704305ca 100644 (file)
@@ -1076,8 +1076,6 @@ out:
        snd_card_free(card);
 }
 
-#ifdef CONFIG_PM_SLEEP
-
 static int snd_at73c213_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
@@ -1109,18 +1107,13 @@ static int snd_at73c213_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend,
+static DEFINE_SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend,
                snd_at73c213_resume);
-#define AT73C213_PM_OPS (&at73c213_pm_ops)
-
-#else
-#define AT73C213_PM_OPS NULL
-#endif
 
 static struct spi_driver at73c213_driver = {
        .driver         = {
                .name   = "at73c213",
-               .pm     = AT73C213_PM_OPS,
+               .pm     = &at73c213_pm_ops,
        },
        .probe          = snd_at73c213_probe,
        .remove         = snd_at73c213_remove,
index 0006c3ddb51d608bcef2b61d42710003fb88cb2a..a82af937485263d402add34b268cc02137288215 100644 (file)
@@ -85,7 +85,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch
                return -EINVAL;
 
        emu->card = card;
-       emu->name = kstrdup(name, GFP_KERNEL);
+       emu->name = kstrdup_const(name, GFP_KERNEL);
        emu->voices = kcalloc(emu->max_voices, sizeof(struct snd_emux_voice),
                              GFP_KERNEL);
        if (emu->name == NULL || emu->voices == NULL)
@@ -140,7 +140,7 @@ int snd_emux_free(struct snd_emux *emu)
        snd_emux_delete_hwdep(emu);
        snd_sf_free(emu->sflist);
        kfree(emu->voices);
-       kfree(emu->name);
+       kfree_const(emu->name);
        kfree(emu);
        return 0;
 }
index 6de605a601e5f89ff7a9c12b36db81eed6d876c3..bd114be537d7aed32f75b955b5c9bd7db199cc2f 100644 (file)
 
 /* some gui mixers can't handle negative ctl values */
 #define SCARLETT2_VOLUME_BIAS 127
-#define SCARLETT2_GAIN_BIAS 70
+
+/* maximum preamp input gain and value
+ * values are from 0 to 70, preamp gain is from 0 to 69 dB
+ */
+#define SCARLETT2_MAX_GAIN_VALUE 70
+#define SCARLETT2_MAX_GAIN_DB 69
 
 /* mixer range from -80dB to +6dB in 0.5dB steps */
 #define SCARLETT2_MIXER_MIN_DB -80
@@ -284,14 +289,22 @@ static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = {
        "Mute Playback Switch", "Dim Playback Switch"
 };
 
-/* Autogain Status Values */
-enum {
-       SCARLETT2_AUTOGAIN_STATUS_STOPPED,
-       SCARLETT2_AUTOGAIN_STATUS_RUNNING,
-       SCARLETT2_AUTOGAIN_STATUS_FAILED,
-       SCARLETT2_AUTOGAIN_STATUS_CANCELLED,
-       SCARLETT2_AUTOGAIN_STATUS_UNKNOWN,
-       SCARLETT2_AUTOGAIN_STATUS_COUNT
+/* The autogain_status is set based on the autogain_switch and
+ * raw_autogain_status values.
+ *
+ * If autogain_switch is set, autogain_status is set to 0 (Running).
+ * The other status values are from the raw_autogain_status value + 1.
+ */
+static const char *const scarlett2_autogain_status_texts[] = {
+       "Running",
+       "Success",
+       "SuccessDRover",
+       "WarnMinGainLimit",
+       "FailDRunder",
+       "FailMaxGainLimit",
+       "FailClipped",
+       "Cancelled",
+       "Invalid"
 };
 
 /* Power Status Values */
@@ -415,7 +428,7 @@ enum {
        SCARLETT2_CONFIG_INPUT_SELECT_SWITCH,
        SCARLETT2_CONFIG_INPUT_LINK_SWITCH,
        SCARLETT2_CONFIG_POWER_EXT,
-       SCARLETT2_CONFIG_POWER_STATUS,
+       SCARLETT2_CONFIG_POWER_LOW,
        SCARLETT2_CONFIG_PCM_INPUT_SWITCH,
        SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN,
        SCARLETT2_CONFIG_COUNT
@@ -723,8 +736,8 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = {
                [SCARLETT2_CONFIG_POWER_EXT] = {
                        .offset = 0x168 },
 
-               [SCARLETT2_CONFIG_POWER_STATUS] = {
-                       .offset = 0x66 }
+               [SCARLETT2_CONFIG_POWER_LOW] = {
+                       .offset = 0x16d }
        }
 };
 
@@ -2835,9 +2848,9 @@ static int scarlett2_autogain_is_running(struct scarlett2_data *private)
 {
        int i;
 
+       /* autogain_status[] is 0 if autogain is running */
        for (i = 0; i < private->info->gain_input_count; i++)
-               if (private->autogain_status[i] ==
-                   SCARLETT2_AUTOGAIN_STATUS_RUNNING)
+               if (!private->autogain_status[i])
                        return 1;
 
        return 0;
@@ -2867,25 +2880,25 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer)
                return err;
 
        /* Translate autogain_switch and raw_autogain_status into
-        * autogain_status
+        * autogain_status.
+        *
+        * When autogain_switch[] is set, the status is the first
+        * element in scarlett2_autogain_status_texts[] (Running). The
+        * subsequent elements correspond to the status value from the
+        * device (raw_autogain_status[]) + 1. The last element is
+        * "Invalid", in case the device reports a status outside the
+        * range of scarlett2_autogain_status_texts[].
         */
        for (i = 0; i < info->gain_input_count; i++)
                if (private->autogain_switch[i])
+                       private->autogain_status[i] = 0;
+               else if (raw_autogain_status[i] <
+                               ARRAY_SIZE(scarlett2_autogain_status_texts) - 1)
                        private->autogain_status[i] =
-                               SCARLETT2_AUTOGAIN_STATUS_RUNNING;
-               else if (raw_autogain_status[i] == 0)
-                       private->autogain_status[i] =
-                               SCARLETT2_AUTOGAIN_STATUS_STOPPED;
-               else if (raw_autogain_status[i] >= 2 &&
-                        raw_autogain_status[i] <= 5)
-                       private->autogain_status[i] =
-                               SCARLETT2_AUTOGAIN_STATUS_FAILED;
-               else if (raw_autogain_status[i] == 6)
-                       private->autogain_status[i] =
-                               SCARLETT2_AUTOGAIN_STATUS_CANCELLED;
+                               raw_autogain_status[i] + 1;
                else
                        private->autogain_status[i] =
-                               SCARLETT2_AUTOGAIN_STATUS_UNKNOWN;
+                               ARRAY_SIZE(scarlett2_autogain_status_texts) - 1;
 
        return 0;
 }
@@ -3111,12 +3124,10 @@ unlock:
 static int scarlett2_autogain_status_ctl_info(
        struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
 {
-       static const char *const values[SCARLETT2_AUTOGAIN_STATUS_COUNT] = {
-               "Stopped", "Running", "Failed", "Cancelled", "Unknown"
-       };
-
        return snd_ctl_enum_info(
-               uinfo, 1, SCARLETT2_AUTOGAIN_STATUS_COUNT, values);
+               uinfo, 1,
+               ARRAY_SIZE(scarlett2_autogain_status_texts),
+               scarlett2_autogain_status_texts);
 }
 
 static const struct snd_kcontrol_new scarlett2_autogain_switch_ctl = {
@@ -3458,7 +3469,7 @@ static int scarlett2_input_gain_ctl_info(struct snd_kcontrol *kctl,
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = elem->channels;
        uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = SCARLETT2_GAIN_BIAS;
+       uinfo->value.integer.max = SCARLETT2_MAX_GAIN_VALUE;
        uinfo->value.integer.step = 1;
 
 unlock:
@@ -3535,7 +3546,7 @@ unlock:
 }
 
 static const DECLARE_TLV_DB_MINMAX(
-       db_scale_scarlett2_gain, -SCARLETT2_GAIN_BIAS * 100, 0
+       db_scale_scarlett2_gain, 0, SCARLETT2_MAX_GAIN_DB * 100
 );
 
 static const struct snd_kcontrol_new scarlett2_input_gain_ctl = {
@@ -6294,8 +6305,7 @@ static int scarlett2_update_power_status(struct usb_mixer_interface *mixer)
 {
        struct scarlett2_data *private = mixer->private_data;
        int err;
-       u8 power_ext;
-       u8 power_status;
+       u8 power_ext, power_low;
 
        private->power_status_updated = 0;
 
@@ -6304,12 +6314,12 @@ static int scarlett2_update_power_status(struct usb_mixer_interface *mixer)
        if (err < 0)
                return err;
 
-       err = scarlett2_usb_get_config(mixer, SCARLETT2_CONFIG_POWER_STATUS,
-                                      1, &power_status);
+       err = scarlett2_usb_get_config(mixer, SCARLETT2_CONFIG_POWER_LOW,
+                                      1, &power_low);
        if (err < 0)
                return err;
 
-       if (power_status > 1)
+       if (power_low)
                private->power_status = SCARLETT2_POWER_STATUS_FAIL;
        else if (power_ext)
                private->power_status = SCARLETT2_POWER_STATUS_EXT;
index 3d4add94e367d63d1329f22ddb78af4264685580..d5409f3879455961182713d24327836219e73457 100644 (file)
@@ -300,9 +300,12 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
        c = 0;
 
        if (bits) {
-               for (; bits && *maps; maps++, bits >>= 1)
+               for (; bits && *maps; maps++, bits >>= 1) {
                        if (bits & 1)
                                chmap->map[c++] = *maps;
+                       if (c == chmap->channels)
+                               break;
+               }
        } else {
                /* If we're missing wChannelConfig, then guess something
                    to make sure the channel map is not skipped entirely */
index 2742bddb887414d7bb97f0efd32325e02b3513f9..a839f8c8b5e6478c9f7b6ec3c8b60e6be4750ecb 100644 (file)
@@ -7,6 +7,7 @@ virtio_snd-objs := \
        virtio_chmap.o \
        virtio_ctl_msg.o \
        virtio_jack.o \
+       virtio_kctl.o \
        virtio_pcm.o \
        virtio_pcm_msg.o \
        virtio_pcm_ops.o
index b158c3cb8e5f5fce75e22306c7707935465bc57f..2da20c6252477cabe4c2dd3adbc29cc422500ee5 100644 (file)
@@ -64,6 +64,9 @@ static void virtsnd_event_dispatch(struct virtio_snd *snd,
        case VIRTIO_SND_EVT_PCM_XRUN:
                virtsnd_pcm_event(snd, event);
                break;
+       case VIRTIO_SND_EVT_CTL_NOTIFY:
+               virtsnd_kctl_event(snd, event);
+               break;
        }
 }
 
@@ -233,6 +236,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
        if (rc)
                return rc;
 
+       if (virtio_has_feature(vdev, VIRTIO_SND_F_CTLS)) {
+               rc = virtsnd_kctl_parse_cfg(snd);
+               if (rc)
+                       return rc;
+       }
+
        if (snd->njacks) {
                rc = virtsnd_jack_build_devs(snd);
                if (rc)
@@ -251,6 +260,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
                        return rc;
        }
 
+       if (snd->nkctls) {
+               rc = virtsnd_kctl_build_devs(snd);
+               if (rc)
+                       return rc;
+       }
+
        return snd_card_register(snd->card);
 }
 
@@ -417,10 +432,16 @@ static const struct virtio_device_id id_table[] = {
        { 0 },
 };
 
+static unsigned int features[] = {
+       VIRTIO_SND_F_CTLS
+};
+
 static struct virtio_driver virtsnd_driver = {
        .driver.name = KBUILD_MODNAME,
        .driver.owner = THIS_MODULE,
        .id_table = id_table,
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
        .validate = virtsnd_validate,
        .probe = virtsnd_probe,
        .remove = virtsnd_remove,
index 86ef3941895ed25c9bfa1d46267bef99f2ad7101..3ceee4e416fc7be8c016064bfe08f26f8fe86fb8 100644 (file)
@@ -31,6 +31,16 @@ struct virtio_snd_queue {
        struct virtqueue *vqueue;
 };
 
+/**
+ * struct virtio_kctl - VirtIO control element.
+ * @kctl: ALSA control element.
+ * @items: Items for the ENUMERATED element type.
+ */
+struct virtio_kctl {
+       struct snd_kcontrol *kctl;
+       struct virtio_snd_ctl_enum_item *items;
+};
+
 /**
  * struct virtio_snd - VirtIO sound card device.
  * @vdev: Underlying virtio device.
@@ -45,6 +55,9 @@ struct virtio_snd_queue {
  * @nsubstreams: Number of PCM substreams.
  * @chmaps: VirtIO channel maps.
  * @nchmaps: Number of channel maps.
+ * @kctl_infos: VirtIO control element information.
+ * @kctls: VirtIO control elements.
+ * @nkctls: Number of control elements.
  */
 struct virtio_snd {
        struct virtio_device *vdev;
@@ -59,6 +72,9 @@ struct virtio_snd {
        u32 nsubstreams;
        struct virtio_snd_chmap_info *chmaps;
        u32 nchmaps;
+       struct virtio_snd_ctl_info *kctl_infos;
+       struct virtio_kctl *kctls;
+       u32 nkctls;
 };
 
 /* Message completion timeout in milliseconds (module parameter). */
@@ -108,4 +124,10 @@ int virtsnd_chmap_parse_cfg(struct virtio_snd *snd);
 
 int virtsnd_chmap_build_devs(struct virtio_snd *snd);
 
+int virtsnd_kctl_parse_cfg(struct virtio_snd *snd);
+
+int virtsnd_kctl_build_devs(struct virtio_snd *snd);
+
+void virtsnd_kctl_event(struct virtio_snd *snd, struct virtio_snd_event *event);
+
 #endif /* VIRTIO_SND_CARD_H */
diff --git a/sound/virtio/virtio_kctl.c b/sound/virtio/virtio_kctl.c
new file mode 100644 (file)
index 0000000..7aa79c0
--- /dev/null
@@ -0,0 +1,477 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2022 OpenSynergy GmbH
+ */
+#include <sound/control.h>
+#include <linux/virtio_config.h>
+
+#include "virtio_card.h"
+
+/* Map for converting VirtIO types to ALSA types. */
+static const snd_ctl_elem_type_t g_v2a_type_map[] = {
+       [VIRTIO_SND_CTL_TYPE_BOOLEAN] = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
+       [VIRTIO_SND_CTL_TYPE_INTEGER] = SNDRV_CTL_ELEM_TYPE_INTEGER,
+       [VIRTIO_SND_CTL_TYPE_INTEGER64] = SNDRV_CTL_ELEM_TYPE_INTEGER64,
+       [VIRTIO_SND_CTL_TYPE_ENUMERATED] = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
+       [VIRTIO_SND_CTL_TYPE_BYTES] = SNDRV_CTL_ELEM_TYPE_BYTES,
+       [VIRTIO_SND_CTL_TYPE_IEC958] = SNDRV_CTL_ELEM_TYPE_IEC958
+};
+
+/* Map for converting VirtIO access rights to ALSA access rights. */
+static const unsigned int g_v2a_access_map[] = {
+       [VIRTIO_SND_CTL_ACCESS_READ] = SNDRV_CTL_ELEM_ACCESS_READ,
+       [VIRTIO_SND_CTL_ACCESS_WRITE] = SNDRV_CTL_ELEM_ACCESS_WRITE,
+       [VIRTIO_SND_CTL_ACCESS_VOLATILE] = SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       [VIRTIO_SND_CTL_ACCESS_INACTIVE] = SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+       [VIRTIO_SND_CTL_ACCESS_TLV_READ] = SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+       [VIRTIO_SND_CTL_ACCESS_TLV_WRITE] = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE,
+       [VIRTIO_SND_CTL_ACCESS_TLV_COMMAND] = SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND
+};
+
+/* Map for converting VirtIO event masks to ALSA event masks. */
+static const unsigned int g_v2a_mask_map[] = {
+       [VIRTIO_SND_CTL_EVT_MASK_VALUE] = SNDRV_CTL_EVENT_MASK_VALUE,
+       [VIRTIO_SND_CTL_EVT_MASK_INFO] = SNDRV_CTL_EVENT_MASK_INFO,
+       [VIRTIO_SND_CTL_EVT_MASK_TLV] = SNDRV_CTL_EVENT_MASK_TLV
+};
+
+/**
+ * virtsnd_kctl_info() - Returns information about the control.
+ * @kcontrol: ALSA control element.
+ * @uinfo: Element information.
+ *
+ * Context: Process context.
+ * Return: 0 on success, -errno on failure.
+ */
+static int virtsnd_kctl_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo)
+{
+       struct virtio_snd *snd = kcontrol->private_data;
+       struct virtio_kctl *kctl = &snd->kctls[kcontrol->private_value];
+       struct virtio_snd_ctl_info *kinfo =
+               &snd->kctl_infos[kcontrol->private_value];
+       unsigned int i;
+
+       uinfo->type = g_v2a_type_map[le32_to_cpu(kinfo->type)];
+       uinfo->count = le32_to_cpu(kinfo->count);
+
+       switch (uinfo->type) {
+       case SNDRV_CTL_ELEM_TYPE_INTEGER:
+               uinfo->value.integer.min =
+                       le32_to_cpu(kinfo->value.integer.min);
+               uinfo->value.integer.max =
+                       le32_to_cpu(kinfo->value.integer.max);
+               uinfo->value.integer.step =
+                       le32_to_cpu(kinfo->value.integer.step);
+
+               break;
+       case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+               uinfo->value.integer64.min =
+                       le64_to_cpu(kinfo->value.integer64.min);
+               uinfo->value.integer64.max =
+                       le64_to_cpu(kinfo->value.integer64.max);
+               uinfo->value.integer64.step =
+                       le64_to_cpu(kinfo->value.integer64.step);
+
+               break;
+       case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+               uinfo->value.enumerated.items =
+                       le32_to_cpu(kinfo->value.enumerated.items);
+               i = uinfo->value.enumerated.item;
+               if (i >= uinfo->value.enumerated.items)
+                       return -EINVAL;
+
+               strscpy(uinfo->value.enumerated.name, kctl->items[i].item,
+                       sizeof(uinfo->value.enumerated.name));
+
+               break;
+       }
+
+       return 0;
+}
+
+/**
+ * virtsnd_kctl_get() - Read the value from the control.
+ * @kcontrol: ALSA control element.
+ * @uvalue: Element value.
+ *
+ * Context: Process context.
+ * Return: 0 on success, -errno on failure.
+ */
+static int virtsnd_kctl_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *uvalue)
+{
+       struct virtio_snd *snd = kcontrol->private_data;
+       struct virtio_snd_ctl_info *kinfo =
+               &snd->kctl_infos[kcontrol->private_value];
+       unsigned int type = le32_to_cpu(kinfo->type);
+       unsigned int count = le32_to_cpu(kinfo->count);
+       struct virtio_snd_msg *msg;
+       struct virtio_snd_ctl_hdr *hdr;
+       struct virtio_snd_ctl_value *kvalue;
+       size_t request_size = sizeof(*hdr);
+       size_t response_size = sizeof(struct virtio_snd_hdr) + sizeof(*kvalue);
+       unsigned int i;
+       int rc;
+
+       msg = virtsnd_ctl_msg_alloc(request_size, response_size, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       virtsnd_ctl_msg_ref(msg);
+
+       hdr = virtsnd_ctl_msg_request(msg);
+       hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_READ);
+       hdr->control_id = cpu_to_le32(kcontrol->private_value);
+
+       rc = virtsnd_ctl_msg_send_sync(snd, msg);
+       if (rc)
+               goto on_failure;
+
+       kvalue = (void *)((u8 *)virtsnd_ctl_msg_response(msg) +
+                         sizeof(struct virtio_snd_hdr));
+
+       switch (type) {
+       case VIRTIO_SND_CTL_TYPE_BOOLEAN:
+       case VIRTIO_SND_CTL_TYPE_INTEGER:
+               for (i = 0; i < count; ++i)
+                       uvalue->value.integer.value[i] =
+                               le32_to_cpu(kvalue->value.integer[i]);
+               break;
+       case VIRTIO_SND_CTL_TYPE_INTEGER64:
+               for (i = 0; i < count; ++i)
+                       uvalue->value.integer64.value[i] =
+                               le64_to_cpu(kvalue->value.integer64[i]);
+               break;
+       case VIRTIO_SND_CTL_TYPE_ENUMERATED:
+               for (i = 0; i < count; ++i)
+                       uvalue->value.enumerated.item[i] =
+                               le32_to_cpu(kvalue->value.enumerated[i]);
+               break;
+       case VIRTIO_SND_CTL_TYPE_BYTES:
+               memcpy(uvalue->value.bytes.data, kvalue->value.bytes, count);
+               break;
+       case VIRTIO_SND_CTL_TYPE_IEC958:
+               memcpy(&uvalue->value.iec958, &kvalue->value.iec958,
+                      sizeof(uvalue->value.iec958));
+               break;
+       }
+
+on_failure:
+       virtsnd_ctl_msg_unref(msg);
+
+       return rc;
+}
+
+/**
+ * virtsnd_kctl_put() - Write the value to the control.
+ * @kcontrol: ALSA control element.
+ * @uvalue: Element value.
+ *
+ * Context: Process context.
+ * Return: 0 on success, -errno on failure.
+ */
+static int virtsnd_kctl_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *uvalue)
+{
+       struct virtio_snd *snd = kcontrol->private_data;
+       struct virtio_snd_ctl_info *kinfo =
+               &snd->kctl_infos[kcontrol->private_value];
+       unsigned int type = le32_to_cpu(kinfo->type);
+       unsigned int count = le32_to_cpu(kinfo->count);
+       struct virtio_snd_msg *msg;
+       struct virtio_snd_ctl_hdr *hdr;
+       struct virtio_snd_ctl_value *kvalue;
+       size_t request_size = sizeof(*hdr) + sizeof(*kvalue);
+       size_t response_size = sizeof(struct virtio_snd_hdr);
+       unsigned int i;
+
+       msg = virtsnd_ctl_msg_alloc(request_size, response_size, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = virtsnd_ctl_msg_request(msg);
+       hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_WRITE);
+       hdr->control_id = cpu_to_le32(kcontrol->private_value);
+
+       kvalue = (void *)((u8 *)hdr + sizeof(*hdr));
+
+       switch (type) {
+       case VIRTIO_SND_CTL_TYPE_BOOLEAN:
+       case VIRTIO_SND_CTL_TYPE_INTEGER:
+               for (i = 0; i < count; ++i)
+                       kvalue->value.integer[i] =
+                               cpu_to_le32(uvalue->value.integer.value[i]);
+               break;
+       case VIRTIO_SND_CTL_TYPE_INTEGER64:
+               for (i = 0; i < count; ++i)
+                       kvalue->value.integer64[i] =
+                               cpu_to_le64(uvalue->value.integer64.value[i]);
+               break;
+       case VIRTIO_SND_CTL_TYPE_ENUMERATED:
+               for (i = 0; i < count; ++i)
+                       kvalue->value.enumerated[i] =
+                               cpu_to_le32(uvalue->value.enumerated.item[i]);
+               break;
+       case VIRTIO_SND_CTL_TYPE_BYTES:
+               memcpy(kvalue->value.bytes, uvalue->value.bytes.data, count);
+               break;
+       case VIRTIO_SND_CTL_TYPE_IEC958:
+               memcpy(&kvalue->value.iec958, &uvalue->value.iec958,
+                      sizeof(kvalue->value.iec958));
+               break;
+       }
+
+       return virtsnd_ctl_msg_send_sync(snd, msg);
+}
+
+/**
+ * virtsnd_kctl_tlv_op() - Perform an operation on the control's metadata.
+ * @kcontrol: ALSA control element.
+ * @op_flag: Operation code (SNDRV_CTL_TLV_OP_XXX).
+ * @size: Size of the TLV data in bytes.
+ * @utlv: TLV data.
+ *
+ * Context: Process context.
+ * Return: 0 on success, -errno on failure.
+ */
+static int virtsnd_kctl_tlv_op(struct snd_kcontrol *kcontrol, int op_flag,
+                              unsigned int size, unsigned int __user *utlv)
+{
+       struct virtio_snd *snd = kcontrol->private_data;
+       struct virtio_snd_msg *msg;
+       struct virtio_snd_ctl_hdr *hdr;
+       unsigned int *tlv;
+       struct scatterlist sg;
+       int rc;
+
+       msg = virtsnd_ctl_msg_alloc(sizeof(*hdr), sizeof(struct virtio_snd_hdr),
+                                   GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       tlv = kzalloc(size, GFP_KERNEL);
+       if (!tlv) {
+               rc = -ENOMEM;
+               goto on_msg_unref;
+       }
+
+       sg_init_one(&sg, tlv, size);
+
+       hdr = virtsnd_ctl_msg_request(msg);
+       hdr->control_id = cpu_to_le32(kcontrol->private_value);
+
+       switch (op_flag) {
+       case SNDRV_CTL_TLV_OP_READ:
+               hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_TLV_READ);
+
+               rc = virtsnd_ctl_msg_send(snd, msg, NULL, &sg, false);
+               if (!rc) {
+                       if (copy_to_user(utlv, tlv, size))
+                               rc = -EFAULT;
+               }
+
+               break;
+       case SNDRV_CTL_TLV_OP_WRITE:
+       case SNDRV_CTL_TLV_OP_CMD:
+               if (op_flag == SNDRV_CTL_TLV_OP_WRITE)
+                       hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_TLV_WRITE);
+               else
+                       hdr->hdr.code =
+                               cpu_to_le32(VIRTIO_SND_R_CTL_TLV_COMMAND);
+
+               if (copy_from_user(tlv, utlv, size)) {
+                       rc = -EFAULT;
+                       goto on_msg_unref;
+               } else {
+                       rc = virtsnd_ctl_msg_send(snd, msg, &sg, NULL, false);
+               }
+
+               break;
+       default:
+               rc = -EINVAL;
+               /* We never get here - we listed all values for op_flag */
+               WARN_ON(1);
+               goto on_msg_unref;
+       }
+       kfree(tlv);
+       return rc;
+
+on_msg_unref:
+       virtsnd_ctl_msg_unref(msg);
+       kfree(tlv);
+
+       return rc;
+}
+
+/**
+ * virtsnd_kctl_get_enum_items() - Query items for the ENUMERATED element type.
+ * @snd: VirtIO sound device.
+ * @cid: Control element ID.
+ *
+ * This function is called during initial device initialization.
+ *
+ * Context: Any context that permits to sleep.
+ * Return: 0 on success, -errno on failure.
+ */
+static int virtsnd_kctl_get_enum_items(struct virtio_snd *snd, unsigned int cid)
+{
+       struct virtio_device *vdev = snd->vdev;
+       struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[cid];
+       struct virtio_kctl *kctl = &snd->kctls[cid];
+       struct virtio_snd_msg *msg;
+       struct virtio_snd_ctl_hdr *hdr;
+       unsigned int n = le32_to_cpu(kinfo->value.enumerated.items);
+       struct scatterlist sg;
+
+       msg = virtsnd_ctl_msg_alloc(sizeof(*hdr),
+                                   sizeof(struct virtio_snd_hdr), GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       kctl->items = devm_kcalloc(&vdev->dev, n, sizeof(*kctl->items),
+                                  GFP_KERNEL);
+       if (!kctl->items) {
+               virtsnd_ctl_msg_unref(msg);
+               return -ENOMEM;
+       }
+
+       sg_init_one(&sg, kctl->items, n * sizeof(*kctl->items));
+
+       hdr = virtsnd_ctl_msg_request(msg);
+       hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_ENUM_ITEMS);
+       hdr->control_id = cpu_to_le32(cid);
+
+       return virtsnd_ctl_msg_send(snd, msg, NULL, &sg, false);
+}
+
+/**
+ * virtsnd_kctl_parse_cfg() - Parse the control element configuration.
+ * @snd: VirtIO sound device.
+ *
+ * This function is called during initial device initialization.
+ *
+ * Context: Any context that permits to sleep.
+ * Return: 0 on success, -errno on failure.
+ */
+int virtsnd_kctl_parse_cfg(struct virtio_snd *snd)
+{
+       struct virtio_device *vdev = snd->vdev;
+       u32 i;
+       int rc;
+
+       virtio_cread_le(vdev, struct virtio_snd_config, controls,
+                       &snd->nkctls);
+       if (!snd->nkctls)
+               return 0;
+
+       snd->kctl_infos = devm_kcalloc(&vdev->dev, snd->nkctls,
+                                      sizeof(*snd->kctl_infos), GFP_KERNEL);
+       if (!snd->kctl_infos)
+               return -ENOMEM;
+
+       snd->kctls = devm_kcalloc(&vdev->dev, snd->nkctls, sizeof(*snd->kctls),
+                                 GFP_KERNEL);
+       if (!snd->kctls)
+               return -ENOMEM;
+
+       rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_CTL_INFO, 0, snd->nkctls,
+                                   sizeof(*snd->kctl_infos), snd->kctl_infos);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < snd->nkctls; ++i) {
+               struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[i];
+               unsigned int type = le32_to_cpu(kinfo->type);
+
+               if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED) {
+                       rc = virtsnd_kctl_get_enum_items(snd, i);
+                       if (rc)
+                               return rc;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * virtsnd_kctl_build_devs() - Build ALSA control elements.
+ * @snd: VirtIO sound device.
+ *
+ * Context: Any context that permits to sleep.
+ * Return: 0 on success, -errno on failure.
+ */
+int virtsnd_kctl_build_devs(struct virtio_snd *snd)
+{
+       unsigned int cid;
+
+       for (cid = 0; cid < snd->nkctls; ++cid) {
+               struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[cid];
+               struct virtio_kctl *kctl = &snd->kctls[cid];
+               struct snd_kcontrol_new kctl_new;
+               unsigned int i;
+               int rc;
+
+               memset(&kctl_new, 0, sizeof(kctl_new));
+
+               kctl_new.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               kctl_new.name = kinfo->name;
+               kctl_new.index = le32_to_cpu(kinfo->index);
+
+               for (i = 0; i < ARRAY_SIZE(g_v2a_access_map); ++i)
+                       if (le32_to_cpu(kinfo->access) & (1 << i))
+                               kctl_new.access |= g_v2a_access_map[i];
+
+               if (kctl_new.access & (SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                                      SNDRV_CTL_ELEM_ACCESS_TLV_WRITE |
+                                      SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND)) {
+                       kctl_new.access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+                       kctl_new.tlv.c = virtsnd_kctl_tlv_op;
+               }
+
+               kctl_new.info = virtsnd_kctl_info;
+               kctl_new.get = virtsnd_kctl_get;
+               kctl_new.put = virtsnd_kctl_put;
+               kctl_new.private_value = cid;
+
+               kctl->kctl = snd_ctl_new1(&kctl_new, snd);
+               if (!kctl->kctl)
+                       return -ENOMEM;
+
+               rc = snd_ctl_add(snd->card, kctl->kctl);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+/**
+ * virtsnd_kctl_event() - Handle the control element event notification.
+ * @snd: VirtIO sound device.
+ * @event: VirtIO sound event.
+ *
+ * Context: Interrupt context.
+ */
+void virtsnd_kctl_event(struct virtio_snd *snd, struct virtio_snd_event *event)
+{
+       struct virtio_snd_ctl_event *kevent =
+               (struct virtio_snd_ctl_event *)event;
+       struct virtio_kctl *kctl;
+       unsigned int cid = le16_to_cpu(kevent->control_id);
+       unsigned int mask = 0;
+       unsigned int i;
+
+       if (cid >= snd->nkctls)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(g_v2a_mask_map); ++i)
+               if (le16_to_cpu(kevent->mask) & (1 << i))
+                       mask |= g_v2a_mask_map[i];
+
+
+       kctl = &snd->kctls[cid];
+
+       snd_ctl_notify(snd->card, mask, &kctl->kctl->id);
+}