Merge tag 'asoc-v5.2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Mon, 6 May 2019 14:14:09 +0000 (16:14 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 6 May 2019 14:14:34 +0000 (16:14 +0200)
ASoC: Updates for v5.2

This is a pretty huge set of changes, it's been a pretty active release
all round but the big thing with this release is the Sound Open Firmware
changes from Intel, providing another DSP framework for use with the
DSPs in their SoCs.  This one works with the firmware of the same name
which is free software (unlike the previous DSP firmwares and framework)
and there has been some interest in adoption by other systems already so
hopefully we will see adoption by other vendors in the future.

Other highlights include:

 - Support for MCLK/sample rate ratio setting in the generic cards.
 - Support for pin switches in the generic cards.
 - A big set of improvements to the TLV320AIC32x4 drivers from Annaliese
   McDermond.
 - New drivers for Freescale audio mixers, several Intel machines,
   several Mediatek machines, Meson G12A, Sound Open Firmware and
   Spreadtrum compressed audio and DMA devices.

45 files changed:
Documentation/sound/kernel-api/writing-an-alsa-driver.rst
MAINTAINERS
include/sound/core.h
include/sound/hdaudio.h
include/sound/memalloc.h
include/sound/seq_kernel.h
sound/core/init.c
sound/core/memalloc.c
sound/core/oss/mixer_oss.c
sound/core/pcm.c
sound/core/seq/oss/seq_oss_device.h
sound/core/seq/oss/seq_oss_rw.c
sound/core/seq/oss/seq_oss_writeq.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_clientmgr.h
sound/core/seq/seq_fifo.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_ports.h
sound/core/sound.c
sound/core/timer.c
sound/drivers/aloop.c
sound/firewire/amdtp-stream.c
sound/firewire/motu/amdtp-motu.c
sound/firewire/motu/motu-protocol-v2.c
sound/firewire/motu/motu.c
sound/firewire/motu/motu.h
sound/hda/ext/hdac_ext_bus.c
sound/hda/hdac_bus.c
sound/isa/gus/gus_mem.c
sound/last.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/ppc/snd_ps3.c
sound/soc/codecs/hdac_hda.c
sound/synth/emux/emux_hwdep.c
sound/synth/emux/soundfont.c
sound/usb/mixer.c
sound/usb/quirks-table.h
sound/usb/usx2y/usX2Yhwdep.c
sound/usb/usx2y/usb_stream.c
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usx2yhwdeppcm.c

index 6b154db..132f5eb 100644 (file)
@@ -324,7 +324,7 @@ to details explained in the following section.
               strcpy(card->driver, "My Chip");
               strcpy(card->shortname, "My Own Chip 123");
               sprintf(card->longname, "%s at 0x%lx irq %i",
-                      card->shortname, chip->ioport, chip->irq);
+                      card->shortname, chip->port, chip->irq);
 
               /* (5) */
               .... /* implemented later */
@@ -437,7 +437,7 @@ Since each component can be properly freed, the single
   strcpy(card->driver, "My Chip");
   strcpy(card->shortname, "My Own Chip 123");
   sprintf(card->longname, "%s at 0x%lx irq %i",
-          card->shortname, chip->ioport, chip->irq);
+          card->shortname, chip->port, chip->irq);
 
 The driver field holds the minimal ID string of the chip. This is used
 by alsa-lib's configurator, so keep it simple but unique. Even the
index 8ebba1b..4819af3 100644 (file)
@@ -3353,7 +3353,7 @@ F:        include/uapi/linux/bsg.h
 BT87X AUDIO DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.alsa-project.org/alsa-kernel.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
 F:     Documentation/sound/cards/bt87x.rst
 F:     sound/pci/bt87x.c
@@ -3406,7 +3406,7 @@ F:        drivers/scsi/FlashPoint.*
 C-MEDIA CMI8788 DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.alsa-project.org/alsa-kernel.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
 F:     sound/pci/oxygen/
 
@@ -5700,7 +5700,7 @@ F:        drivers/edac/qcom_edac.c
 EDIROL UA-101/UA-1000 DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.alsa-project.org/alsa-kernel.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
 F:     sound/usb/misc/ua101.c
 
@@ -6040,7 +6040,7 @@ F:        include/linux/f75375s.h
 FIREWIRE AUDIO DRIVERS
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.alsa-project.org/alsa-kernel.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
 F:     sound/firewire/
 
@@ -11606,7 +11606,7 @@ F:      Documentation/devicetree/bindings/opp/
 OPL4 DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.alsa-project.org/alsa-kernel.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
 F:     sound/drivers/opl4/
 
@@ -14504,7 +14504,6 @@ M:      Takashi Iwai <tiwai@suse.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://www.alsa-project.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
-T:     git git://git.alsa-project.org/alsa-kernel.git
 Q:     http://patchwork.kernel.org/project/alsa-devel/list/
 S:     Maintained
 F:     Documentation/sound/
@@ -16114,7 +16113,7 @@ F:      drivers/usb/storage/
 USB MIDI DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.alsa-project.org/alsa-kernel.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
 F:     sound/usb/midi.*
 
index e923c23..c90ebbc 100644 (file)
@@ -226,7 +226,6 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
 
 /* init.c */
 
-extern struct snd_card *snd_cards[SNDRV_CARDS];
 int snd_card_locked(int card);
 #if IS_ENABLED(CONFIG_SND_MIXER_OSS)
 #define SND_MIXER_OSS_NOTIFY_REGISTER  0
@@ -251,7 +250,20 @@ int snd_card_add_dev_attr(struct snd_card *card,
 int snd_component_add(struct snd_card *card, const char *component);
 int snd_card_file_add(struct snd_card *card, struct file *file);
 int snd_card_file_remove(struct snd_card *card, struct file *file);
-#define snd_card_unref(card)   put_device(&(card)->card_dev)
+
+struct snd_card *snd_card_ref(int card);
+
+/**
+ * snd_card_unref - Unreference the card object
+ * @card: the card object to unreference
+ *
+ * Call this function for the card object that was obtained via snd_card_ref()
+ * or snd_lookup_minor_data().
+ */
+static inline void snd_card_unref(struct snd_card *card)
+{
+       put_device(&card->card_dev);
+}
 
 #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
 
index 45f944d..ca1d9a7 100644 (file)
@@ -297,7 +297,7 @@ struct hdac_rb {
  * @num_streams: streams supported
  * @idx: HDA link index
  * @hlink_list: link list of HDA links
- * @lock: lock for link mgmt
+ * @lock: lock for link and display power mgmt
  * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
  */
 struct hdac_bus {
@@ -363,6 +363,7 @@ struct hdac_bus {
        /* locks */
        spinlock_t reg_lock;
        struct mutex cmd_mutex;
+       struct mutex lock;
 
        /* DRM component interface */
        struct drm_audio_component *audio_component;
@@ -373,11 +374,9 @@ struct hdac_bus {
        int num_streams;
        int idx;
 
+       /* link management */
        struct list_head hlink_list;
-
-       struct mutex lock;
        bool cmd_dma_state;
-
 };
 
 int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
index 1ac0dd8..4c6f3b5 100644 (file)
@@ -151,9 +151,5 @@ int snd_dma_alloc_pages_fallback(int type, struct device *dev, size_t size,
                                  struct snd_dma_buffer *dmab);
 void snd_dma_free_pages(struct snd_dma_buffer *dmab);
 
-/* basic memory allocation functions */
-void *snd_malloc_pages(size_t size, gfp_t gfp_flags);
-void snd_free_pages(void *ptr, size_t size);
-
 #endif /* __SOUND_MEMALLOC_H */
 
index 4b9ee30..c7a5433 100644 (file)
@@ -73,7 +73,8 @@ __printf(3, 4)
 int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
                                 const char *name_fmt, ...);
 int snd_seq_delete_kernel_client(int client);
-int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, int atomic, int hop);
+int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
+                                 struct file *file, bool blocking);
 int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event *ev, int atomic, int hop);
 int snd_seq_kernel_client_ctl(int client, unsigned int cmd, void *arg);
 
index 079c12d..d64416f 100644 (file)
@@ -49,8 +49,7 @@ static const struct file_operations snd_shutdown_f_ops;
 
 /* locked for registering/using */
 static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS);
-struct snd_card *snd_cards[SNDRV_CARDS];
-EXPORT_SYMBOL(snd_cards);
+static struct snd_card *snd_cards[SNDRV_CARDS];
 
 static DEFINE_MUTEX(snd_card_mutex);
 
@@ -268,6 +267,26 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
 }
 EXPORT_SYMBOL(snd_card_new);
 
+/**
+ * snd_card_ref - Get the card object from the index
+ * @idx: the card index
+ *
+ * Returns a card object corresponding to the given index or NULL if not found.
+ * Release the object via snd_card_unref().
+ */
+struct snd_card *snd_card_ref(int idx)
+{
+       struct snd_card *card;
+
+       mutex_lock(&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);
+
 /* return non-zero if a card is already locked */
 int snd_card_locked(int card)
 {
index eb97423..9f48e1d 100644 (file)
 #endif
 #include <sound/memalloc.h>
 
-/*
- *
- *  Generic memory allocators
- *
- */
-
-/**
- * snd_malloc_pages - allocate pages with the given size
- * @size: the size to allocate in bytes
- * @gfp_flags: the allocation conditions, GFP_XXX
- *
- * Allocates the physically contiguous pages with the given size.
- *
- * Return: The pointer of the buffer, or %NULL if no enough memory.
- */
-void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
-{
-       int pg;
-
-       if (WARN_ON(!size))
-               return NULL;
-       if (WARN_ON(!gfp_flags))
-               return NULL;
-       gfp_flags |= __GFP_COMP;        /* compound page lets parts be mapped */
-       pg = get_order(size);
-       return (void *) __get_free_pages(gfp_flags, pg);
-}
-EXPORT_SYMBOL(snd_malloc_pages);
-
-/**
- * snd_free_pages - release the pages
- * @ptr: the buffer pointer to release
- * @size: the allocated buffer size
- *
- * Releases the buffer allocated via snd_malloc_pages().
- */
-void snd_free_pages(void *ptr, size_t size)
-{
-       int pg;
-
-       if (ptr == NULL)
-               return;
-       pg = get_order(size);
-       free_pages((unsigned long) ptr, pg);
-}
-EXPORT_SYMBOL(snd_free_pages);
-
 /*
  *
  *  Bus-specific memory allocators
@@ -190,8 +143,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
        dmab->bytes = 0;
        switch (type) {
        case SNDRV_DMA_TYPE_CONTINUOUS:
-               dmab->area = snd_malloc_pages(size,
-                                       (__force gfp_t)(unsigned long)device);
+               dmab->area = alloc_pages_exact(size,
+                                              (__force gfp_t)(unsigned long)device);
                dmab->addr = 0;
                break;
 #ifdef CONFIG_HAS_DMA
@@ -275,7 +228,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
 {
        switch (dmab->dev.type) {
        case SNDRV_DMA_TYPE_CONTINUOUS:
-               snd_free_pages(dmab->area, dmab->bytes);
+               free_pages_exact(dmab->area, dmab->bytes);
                break;
 #ifdef CONFIG_HAS_DMA
 #ifdef CONFIG_GENERIC_ALLOCATOR
index 64d904b..c861867 100644 (file)
@@ -1403,24 +1403,32 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
 
 static int __init alsa_mixer_oss_init(void)
 {
+       struct snd_card *card;
        int idx;
        
        snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
        for (idx = 0; idx < SNDRV_CARDS; idx++) {
-               if (snd_cards[idx])
-                       snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
+               card = snd_card_ref(idx);
+               if (card) {
+                       snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_REGISTER);
+                       snd_card_unref(card);
+               }
        }
        return 0;
 }
 
 static void __exit alsa_mixer_oss_exit(void)
 {
+       struct snd_card *card;
        int idx;
 
        snd_mixer_oss_notify_callback = NULL;
        for (idx = 0; idx < SNDRV_CARDS; idx++) {
-               if (snd_cards[idx])
-                       snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
+               card = snd_card_ref(idx);
+               if (card) {
+                       snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_FREE);
+                       snd_card_unref(card);
+               }
        }
 }
 
index 7b63aee..998e477 100644 (file)
@@ -959,22 +959,22 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                return -ENOMEM;
 
        size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
-       runtime->status = snd_malloc_pages(size, GFP_KERNEL);
+       runtime->status = alloc_pages_exact(size, GFP_KERNEL);
        if (runtime->status == NULL) {
                kfree(runtime);
                return -ENOMEM;
        }
-       memset((void*)runtime->status, 0, size);
+       memset(runtime->status, 0, size);
 
        size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
-       runtime->control = snd_malloc_pages(size, GFP_KERNEL);
+       runtime->control = alloc_pages_exact(size, GFP_KERNEL);
        if (runtime->control == NULL) {
-               snd_free_pages((void*)runtime->status,
+               free_pages_exact(runtime->status,
                               PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
                kfree(runtime);
                return -ENOMEM;
        }
-       memset((void*)runtime->control, 0, size);
+       memset(runtime->control, 0, size);
 
        init_waitqueue_head(&runtime->sleep);
        init_waitqueue_head(&runtime->tsleep);
@@ -1000,9 +1000,9 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
        runtime = substream->runtime;
        if (runtime->private_free != NULL)
                runtime->private_free(runtime);
-       snd_free_pages((void*)runtime->status,
+       free_pages_exact(runtime->status,
                       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
-       snd_free_pages((void*)runtime->control,
+       free_pages_exact(runtime->control,
                       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
        kfree(runtime->hw_constraints.rules);
        /* Avoid concurrent access to runtime via PCM timer interface */
index 2d0e9ea..77eb1fe 100644 (file)
@@ -30,6 +30,7 @@
 #include <sound/rawmidi.h>
 #include <sound/seq_kernel.h>
 #include <sound/info.h>
+#include "../seq_clientmgr.h"
 
 /* max. applications */
 #define SNDRV_SEQ_OSS_MAX_CLIENTS      16
@@ -150,11 +151,16 @@ snd_seq_oss_dispatch(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int a
        return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
 }
 
-/* ioctl */
+/* ioctl for writeq */
 static inline int
 snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg)
 {
-       return snd_seq_kernel_client_ctl(dp->cseq, type, arg);
+       int err;
+
+       snd_seq_client_ioctl_lock(dp->cseq);
+       err = snd_seq_kernel_client_ctl(dp->cseq, type, arg);
+       snd_seq_client_ioctl_unlock(dp->cseq);
+       return err;
 }
 
 /* fill the addresses in header */
index 30886f5..eb1ef12 100644 (file)
@@ -180,14 +180,11 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
                return 0; /* invalid event - no need to insert queue */
 
        event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer);
-       if (dp->timer->realtime || !dp->timer->running) {
+       if (dp->timer->realtime || !dp->timer->running)
                snd_seq_oss_dispatch(dp, &event, 0, 0);
-       } else {
-               if (is_nonblock_mode(dp->file_mode))
-                       rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, 0, 0);
-               else
-                       rc = snd_seq_kernel_client_enqueue_blocking(dp->cseq, &event, opt, 0, 0);
-       }
+       else
+               rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, opt,
+                                                  !is_nonblock_mode(dp->file_mode));
        return rc;
 }
                
index 5e04f4d..b2f6961 100644 (file)
@@ -116,7 +116,7 @@ snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
                rec->t.code = SEQ_SYNCTIMER;
                rec->t.time = time;
                q->sync_event_put = 1;
-               snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
+               snd_seq_kernel_client_enqueue(dp->cseq, &ev, NULL, true);
        }
 
        wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
index 38e7dea..c0227a6 100644 (file)
@@ -179,6 +179,41 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
        return client;
 }
 
+/* Take refcount and perform ioctl_mutex lock on the given client;
+ * used only for OSS sequencer
+ * Unlock via snd_seq_client_ioctl_unlock() below
+ */
+bool snd_seq_client_ioctl_lock(int clientid)
+{
+       struct snd_seq_client *client;
+
+       client = snd_seq_client_use_ptr(clientid);
+       if (!client)
+               return false;
+       mutex_lock(&client->ioctl_mutex);
+       /* The client isn't unrefed here; see snd_seq_client_ioctl_unlock() */
+       return true;
+}
+EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_lock);
+
+/* Unlock and unref the given client; for OSS sequencer use only */
+void snd_seq_client_ioctl_unlock(int clientid)
+{
+       struct snd_seq_client *client;
+
+       client = snd_seq_client_use_ptr(clientid);
+       if (WARN_ON(!client))
+               return;
+       mutex_unlock(&client->ioctl_mutex);
+       /* The doubly unrefs below are intentional; the first one releases the
+        * leftover from snd_seq_client_ioctl_lock() above, and the second one
+        * is for releasing snd_seq_client_use_ptr() in this function
+        */
+       snd_seq_client_unlock(client);
+       snd_seq_client_unlock(client);
+}
+EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_unlock);
+
 static void usage_alloc(struct snd_seq_usage *res, int num)
 {
        res->cur += num;
@@ -203,7 +238,6 @@ int __init client_init_data(void)
 
 static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
 {
-       unsigned long flags;
        int c;
        struct snd_seq_client *client;
 
@@ -224,7 +258,7 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
        mutex_init(&client->ioctl_mutex);
 
        /* find free slot in the client table */
-       spin_lock_irqsave(&clients_lock, flags);
+       spin_lock_irq(&clients_lock);
        if (client_index < 0) {
                for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
                     c < SNDRV_SEQ_MAX_CLIENTS;
@@ -232,17 +266,17 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
                        if (clienttab[c] || clienttablock[c])
                                continue;
                        clienttab[client->number = c] = client;
-                       spin_unlock_irqrestore(&clients_lock, flags);
+                       spin_unlock_irq(&clients_lock);
                        return client;
                }
        } else {
                if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
                        clienttab[client->number = client_index] = client;
-                       spin_unlock_irqrestore(&clients_lock, flags);
+                       spin_unlock_irq(&clients_lock);
                        return client;
                }
        }
-       spin_unlock_irqrestore(&clients_lock, flags);
+       spin_unlock_irq(&clients_lock);
        snd_seq_pool_delete(&client->pool);
        kfree(client);
        return NULL;    /* no free slot found or busy, return failure code */
@@ -251,23 +285,21 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
 
 static int seq_free_client1(struct snd_seq_client *client)
 {
-       unsigned long flags;
-
        if (!client)
                return 0;
-       spin_lock_irqsave(&clients_lock, flags);
+       spin_lock_irq(&clients_lock);
        clienttablock[client->number] = 1;
        clienttab[client->number] = NULL;
-       spin_unlock_irqrestore(&clients_lock, flags);
+       spin_unlock_irq(&clients_lock);
        snd_seq_delete_all_ports(client);
        snd_seq_queue_client_leave(client->number);
        snd_use_lock_sync(&client->use_lock);
        snd_seq_queue_client_termination(client->number);
        if (client->pool)
                snd_seq_pool_delete(&client->pool);
-       spin_lock_irqsave(&clients_lock, flags);
+       spin_lock_irq(&clients_lock);
        clienttablock[client->number] = 0;
-       spin_unlock_irqrestore(&clients_lock, flags);
+       spin_unlock_irq(&clients_lock);
        return 0;
 }
 
@@ -1900,20 +1932,14 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
        int result;
        struct snd_seq_client *sender = NULL;
        struct snd_seq_client_port *sport = NULL;
-       struct snd_seq_subscribers *p;
 
        result = -EINVAL;
        if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
                goto __end;
        if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
                goto __end;
-       p = snd_seq_port_get_subscription(&sport->c_src, &subs->dest);
-       if (p) {
-               result = 0;
-               *subs = p->info;
-       } else
-               result = -ENOENT;
-
+       result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest,
+                                              subs);
       __end:
        if (sport)
                snd_seq_port_unlock(sport);
@@ -2227,12 +2253,13 @@ int snd_seq_delete_kernel_client(int client)
 }
 EXPORT_SYMBOL(snd_seq_delete_kernel_client);
 
-/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue
- * and snd_seq_kernel_client_enqueue_blocking
+/*
+ * exported, called by kernel clients to enqueue events (w/o blocking)
+ *
+ * RETURN VALUE: zero if succeed, negative if error
  */
-static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
-                                struct file *file, int blocking,
-                                int atomic, int hop)
+int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
+                                 struct file *file, bool blocking)
 {
        struct snd_seq_client *cptr;
        int result;
@@ -2255,41 +2282,21 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
        if (cptr == NULL)
                return -EINVAL;
        
-       if (! cptr->accept_output)
+       if (!cptr->accept_output) {
                result = -EPERM;
-       else /* send it */
+       } else { /* send it */
+               mutex_lock(&cptr->ioctl_mutex);
                result = snd_seq_client_enqueue_event(cptr, ev, file, blocking,
-                                                     atomic, hop, NULL);
+                                                     false, 0,
+                                                     &cptr->ioctl_mutex);
+               mutex_unlock(&cptr->ioctl_mutex);
+       }
 
        snd_seq_client_unlock(cptr);
        return result;
 }
-
-/*
- * exported, called by kernel clients to enqueue events (w/o blocking)
- *
- * RETURN VALUE: zero if succeed, negative if error
- */
-int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,
-                                 int atomic, int hop)
-{
-       return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);
-}
 EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
 
-/*
- * exported, called by kernel clients to enqueue events (with blocking)
- *
- * RETURN VALUE: zero if succeed, negative if error
- */
-int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,
-                                          struct file *file,
-                                          int atomic, int hop)
-{
-       return kernel_client_enqueue(client, ev, file, 1, atomic, hop);
-}
-EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
-
 /* 
  * exported, called by kernel clients to dispatch events directly to other
  * clients, bypassing the queues.  Event time-stamp will be updated.
index 0611e1e..28a51dc 100644 (file)
@@ -93,14 +93,14 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid);
 /* dispatch event to client(s) */
 int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop);
 
-/* exported to other modules */
-int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, int atomic, int hop);
-int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,
-                                          struct file *file, int atomic, int hop);
 int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait);
 int snd_seq_client_notify_subscription(int client, int port,
                                       struct snd_seq_port_subscribe *info, int evtype);
 
+/* only for OSS sequencer */
+bool snd_seq_client_ioctl_lock(int clientid);
+void snd_seq_client_ioctl_unlock(int clientid);
+
 extern int seq_client_load[15];
 
 #endif
index 72c0302..97ee89c 100644 (file)
@@ -98,18 +98,17 @@ static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f);
 void snd_seq_fifo_clear(struct snd_seq_fifo *f)
 {
        struct snd_seq_event_cell *cell;
-       unsigned long flags;
 
        /* clear overflow flag */
        atomic_set(&f->overflow, 0);
 
        snd_use_lock_sync(&f->use_lock);
-       spin_lock_irqsave(&f->lock, flags);
+       spin_lock_irq(&f->lock);
        /* drain the fifo */
        while ((cell = fifo_cell_out(f)) != NULL) {
                snd_seq_cell_free(cell);
        }
-       spin_unlock_irqrestore(&f->lock, flags);
+       spin_unlock_irq(&f->lock);
 }
 
 
@@ -195,9 +194,9 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
                }
                set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&f->input_sleep, &wait);
-               spin_unlock_irq(&f->lock);
+               spin_unlock_irqrestore(&f->lock, flags);
                schedule();
-               spin_lock_irq(&f->lock);
+               spin_lock_irqsave(&f->lock, flags);
                remove_wait_queue(&f->input_sleep, &wait);
                if (signal_pending(current)) {
                        spin_unlock_irqrestore(&f->lock, flags);
@@ -239,7 +238,6 @@ int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file,
 /* change the size of pool; all old events are removed */
 int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
 {
-       unsigned long flags;
        struct snd_seq_pool *newpool, *oldpool;
        struct snd_seq_event_cell *cell, *next, *oldhead;
 
@@ -255,7 +253,7 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
                return -ENOMEM;
        }
 
-       spin_lock_irqsave(&f->lock, flags);
+       spin_lock_irq(&f->lock);
        /* remember old pool */
        oldpool = f->pool;
        oldhead = f->head;
@@ -265,7 +263,7 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
        f->tail = NULL;
        f->cells = 0;
        /* NOTE: overflow flag is not cleared */
-       spin_unlock_irqrestore(&f->lock, flags);
+       spin_unlock_irq(&f->lock);
 
        /* close the old pool and wait until all users are gone */
        snd_seq_pool_mark_closing(oldpool);
index 5b03882..19b718e 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/sched/signal.h>
-#include <linux/vmalloc.h>
+#include <linux/mm.h>
 #include <sound/core.h>
 
 #include <sound/seq_kernel.h>
@@ -244,13 +244,13 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
 
                set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&pool->output_sleep, &wait);
-               spin_unlock_irq(&pool->lock);
+               spin_unlock_irqrestore(&pool->lock, flags);
                if (mutexp)
                        mutex_unlock(mutexp);
                schedule();
                if (mutexp)
                        mutex_lock(mutexp);
-               spin_lock_irq(&pool->lock);
+               spin_lock_irqsave(&pool->lock, flags);
                remove_wait_queue(&pool->output_sleep, &wait);
                /* interrupted? */
                if (signal_pending(current)) {
@@ -384,21 +384,20 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
 {
        int cell;
        struct snd_seq_event_cell *cellptr;
-       unsigned long flags;
 
        if (snd_BUG_ON(!pool))
                return -EINVAL;
 
-       cellptr = vmalloc(array_size(sizeof(struct snd_seq_event_cell),
-                                    pool->size));
+       cellptr = kvmalloc_array(sizeof(struct snd_seq_event_cell), pool->size,
+                                GFP_KERNEL);
        if (!cellptr)
                return -ENOMEM;
 
        /* add new cells to the free cell list */
-       spin_lock_irqsave(&pool->lock, flags);
+       spin_lock_irq(&pool->lock);
        if (pool->ptr) {
-               spin_unlock_irqrestore(&pool->lock, flags);
-               vfree(cellptr);
+               spin_unlock_irq(&pool->lock);
+               kvfree(cellptr);
                return 0;
        }
 
@@ -416,7 +415,7 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
        /* init statistics */
        pool->max_used = 0;
        pool->total_elements = pool->size;
-       spin_unlock_irqrestore(&pool->lock, flags);
+       spin_unlock_irq(&pool->lock);
        return 0;
 }
 
@@ -435,7 +434,6 @@ void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
 /* remove events */
 int snd_seq_pool_done(struct snd_seq_pool *pool)
 {
-       unsigned long flags;
        struct snd_seq_event_cell *ptr;
 
        if (snd_BUG_ON(!pool))
@@ -449,18 +447,18 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
                schedule_timeout_uninterruptible(1);
        
        /* release all resources */
-       spin_lock_irqsave(&pool->lock, flags);
+       spin_lock_irq(&pool->lock);
        ptr = pool->ptr;
        pool->ptr = NULL;
        pool->free = NULL;
        pool->total_elements = 0;
-       spin_unlock_irqrestore(&pool->lock, flags);
+       spin_unlock_irq(&pool->lock);
 
-       vfree(ptr);
+       kvfree(ptr);
 
-       spin_lock_irqsave(&pool->lock, flags);
+       spin_lock_irq(&pool->lock);
        pool->closing = 0;
-       spin_unlock_irqrestore(&pool->lock, flags);
+       spin_unlock_irq(&pool->lock);
 
        return 0;
 }
index 24d90ab..ac7556a 100644 (file)
@@ -128,7 +128,6 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
 struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
                                                int port)
 {
-       unsigned long flags;
        struct snd_seq_client_port *new_port, *p;
        int num = -1;
        
@@ -157,7 +156,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
 
        num = port >= 0 ? port : 0;
        mutex_lock(&client->ports_mutex);
-       write_lock_irqsave(&client->ports_lock, flags);
+       write_lock_irq(&client->ports_lock);
        list_for_each_entry(p, &client->ports_list_head, list) {
                if (p->addr.port > num)
                        break;
@@ -169,7 +168,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
        client->num_ports++;
        new_port->addr.port = num;      /* store the port number in the port */
        sprintf(new_port->name, "port-%d", num);
-       write_unlock_irqrestore(&client->ports_lock, flags);
+       write_unlock_irq(&client->ports_lock);
        mutex_unlock(&client->ports_mutex);
 
        return new_port;
@@ -283,11 +282,10 @@ static int port_delete(struct snd_seq_client *client,
 /* delete a port with the given port id */
 int snd_seq_delete_port(struct snd_seq_client *client, int port)
 {
-       unsigned long flags;
        struct snd_seq_client_port *found = NULL, *p;
 
        mutex_lock(&client->ports_mutex);
-       write_lock_irqsave(&client->ports_lock, flags);
+       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 */
@@ -297,7 +295,7 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
                        break;
                }
        }
-       write_unlock_irqrestore(&client->ports_lock, flags);
+       write_unlock_irq(&client->ports_lock);
        mutex_unlock(&client->ports_mutex);
        if (found)
                return port_delete(client, found);
@@ -308,7 +306,6 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
 /* delete the all ports belonging to the given client */
 int snd_seq_delete_all_ports(struct snd_seq_client *client)
 {
-       unsigned long flags;
        struct list_head deleted_list;
        struct snd_seq_client_port *port, *tmp;
        
@@ -316,7 +313,7 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
         * clear the port list in the client data.
         */
        mutex_lock(&client->ports_mutex);
-       write_lock_irqsave(&client->ports_lock, flags);
+       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);
@@ -324,7 +321,7 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
                INIT_LIST_HEAD(&deleted_list);
        }
        client->num_ports = 0;
-       write_unlock_irqrestore(&client->ports_lock, flags);
+       write_unlock_irq(&client->ports_lock);
 
        /* remove each port in deleted_list */
        list_for_each_entry_safe(port, tmp, &deleted_list, list) {
@@ -550,10 +547,10 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
                list_del_init(list);
        grp->exclusive = 0;
        write_unlock_irq(&grp->list_lock);
-       up_write(&grp->list_mutex);
 
        if (!empty)
                unsubscribe_port(client, port, grp, &subs->info, ack);
+       up_write(&grp->list_mutex);
 }
 
 /* connect two ports */
@@ -635,20 +632,23 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
 
 
 /* get matched subscriber */
-struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
-                                                         struct snd_seq_addr *dest_addr)
+int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
+                                 struct snd_seq_addr *dest_addr,
+                                 struct snd_seq_port_subscribe *subs)
 {
-       struct snd_seq_subscribers *s, *found = NULL;
+       struct snd_seq_subscribers *s;
+       int err = -ENOENT;
 
        down_read(&src_grp->list_mutex);
        list_for_each_entry(s, &src_grp->list_head, src_list) {
                if (addr_match(dest_addr, &s->info.dest)) {
-                       found = s;
+                       *subs = s->info;
+                       err = 0;
                        break;
                }
        }
        up_read(&src_grp->list_mutex);
-       return found;
+       return err;
 }
 
 /*
index 26bd71f..06003b3 100644 (file)
@@ -135,7 +135,8 @@ int snd_seq_port_subscribe(struct snd_seq_client_port *port,
                           struct snd_seq_port_subscribe *info);
 
 /* get matched subscriber */
-struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
-                                                         struct snd_seq_addr *dest_addr);
+int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
+                                 struct snd_seq_addr *dest_addr,
+                                 struct snd_seq_port_subscribe *subs);
 
 #endif
index b30f027..a9ad437 100644 (file)
@@ -134,8 +134,11 @@ static struct snd_minor *autoload_device(unsigned int minor)
        if (dev == SNDRV_MINOR_CONTROL) {
                /* /dev/aloadC? */
                int card = SNDRV_MINOR_CARD(minor);
-               if (snd_cards[card] == NULL)
+               struct snd_card *ref = snd_card_ref(card);
+               if (!ref)
                        snd_request_card(card);
+               else
+                       snd_card_unref(ref);
        } else if (dev == SNDRV_MINOR_GLOBAL) {
                /* /dev/aloadSEQ */
                snd_request_other(minor);
index 61a0cec..d23efec 100644 (file)
@@ -38,6 +38,7 @@
 
 /* internal flags */
 #define SNDRV_TIMER_IFLG_PAUSED                0x00010000
+#define SNDRV_TIMER_IFLG_DEAD          0x00020000
 
 #if IS_ENABLED(CONFIG_SND_HRTIMER)
 #define DEFAULT_TIMER_LIMIT 4
@@ -254,19 +255,20 @@ int snd_timer_open(struct snd_timer_instance **ti,
        struct snd_timer_instance *timeri = NULL;
        int err;
 
+       mutex_lock(&register_mutex);
        if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
                /* open a slave instance */
                if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
                    tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
                        pr_debug("ALSA: timer: invalid slave class %i\n",
                                 tid->dev_sclass);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto unlock;
                }
-               mutex_lock(&register_mutex);
                timeri = snd_timer_instance_new(owner, NULL);
                if (!timeri) {
-                       mutex_unlock(&register_mutex);
-                       return -ENOMEM;
+                       err = -ENOMEM;
+                       goto unlock;
                }
                timeri->slave_class = tid->dev_sclass;
                timeri->slave_id = tid->device;
@@ -277,13 +279,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
                        snd_timer_close_locked(timeri);
                        timeri = NULL;
                }
-               mutex_unlock(&register_mutex);
-               *ti = timeri;
-               return err;
+               goto unlock;
        }
 
        /* open a master instance */
-       mutex_lock(&register_mutex);
        timer = snd_timer_find(tid);
 #ifdef CONFIG_MODULES
        if (!timer) {
@@ -294,25 +293,26 @@ int snd_timer_open(struct snd_timer_instance **ti,
        }
 #endif
        if (!timer) {
-               mutex_unlock(&register_mutex);
-               return -ENODEV;
+               err = -ENODEV;
+               goto unlock;
        }
        if (!list_empty(&timer->open_list_head)) {
                timeri = list_entry(timer->open_list_head.next,
                                    struct snd_timer_instance, open_list);
                if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
-                       mutex_unlock(&register_mutex);
-                       return -EBUSY;
+                       err = -EBUSY;
+                       timeri = NULL;
+                       goto unlock;
                }
        }
        if (timer->num_instances >= timer->max_instances) {
-               mutex_unlock(&register_mutex);
-               return -EBUSY;
+               err = -EBUSY;
+               goto unlock;
        }
        timeri = snd_timer_instance_new(owner, timer);
        if (!timeri) {
-               mutex_unlock(&register_mutex);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto unlock;
        }
        /* take a card refcount for safe disconnection */
        if (timer->card)
@@ -321,16 +321,16 @@ int snd_timer_open(struct snd_timer_instance **ti,
        timeri->slave_id = slave_id;
 
        if (list_empty(&timer->open_list_head) && timer->hw.open) {
-               int err = timer->hw.open(timer);
+               err = timer->hw.open(timer);
                if (err) {
                        kfree(timeri->owner);
                        kfree(timeri);
+                       timeri = NULL;
 
                        if (timer->card)
                                put_device(&timer->card->card_dev);
                        module_put(timer->module);
-                       mutex_unlock(&register_mutex);
-                       return err;
+                       goto unlock;
                }
        }
 
@@ -341,6 +341,8 @@ int snd_timer_open(struct snd_timer_instance **ti,
                snd_timer_close_locked(timeri);
                timeri = NULL;
        }
+
+ unlock:
        mutex_unlock(&register_mutex);
        *ti = timeri;
        return err;
@@ -353,15 +355,20 @@ EXPORT_SYMBOL(snd_timer_open);
  */
 static int snd_timer_close_locked(struct snd_timer_instance *timeri)
 {
-       struct snd_timer *timer = NULL;
+       struct snd_timer *timer = timeri->timer;
        struct snd_timer_instance *slave, *tmp;
 
+       if (timer) {
+               spin_lock_irq(&timer->lock);
+               timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
+               spin_unlock_irq(&timer->lock);
+       }
+
        list_del(&timeri->open_list);
 
        /* force to stop the timer */
        snd_timer_stop(timeri);
 
-       timer = timeri->timer;
        if (timer) {
                timer->num_instances--;
                /* wait, until the active callback is finished */
@@ -497,6 +504,10 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
                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;
@@ -541,11 +552,16 @@ 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) {
-               spin_unlock_irqrestore(&slave_active_lock, flags);
-               return -EBUSY;
+               err = -EBUSY;
+               goto unlock;
        }
        timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
        if (timeri->master && timeri->timer) {
@@ -556,8 +572,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri,
                                  SNDRV_TIMER_EVENT_CONTINUE);
                spin_unlock(&timeri->timer->lock);
        }
+       err = 1; /* delayed start */
+ unlock:
        spin_unlock_irqrestore(&slave_active_lock, flags);
-       return 1; /* delayed start */
+       return err;
 }
 
 /* stop/pause a master timer */
@@ -720,6 +738,46 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
        timer->sticks = ticks;
 }
 
+/* call callbacks in timer ack list */
+static void snd_timer_process_callbacks(struct snd_timer *timer,
+                                       struct list_head *head)
+{
+       struct snd_timer_instance *ti;
+       unsigned long resolution, ticks;
+
+       while (!list_empty(head)) {
+               ti = list_first_entry(head, struct snd_timer_instance,
+                                     ack_list);
+
+               /* remove from ack_list and make empty */
+               list_del_init(&ti->ack_list);
+
+               if (!(ti->flags & SNDRV_TIMER_IFLG_DEAD)) {
+                       ticks = ti->pticks;
+                       ti->pticks = 0;
+                       resolution = ti->resolution;
+                       ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
+                       spin_unlock(&timer->lock);
+                       if (ti->callback)
+                               ti->callback(ti, resolution, ticks);
+                       spin_lock(&timer->lock);
+                       ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
+               }
+       }
+}
+
+/* clear pending instances from ack list */
+static void snd_timer_clear_callbacks(struct snd_timer *timer,
+                                     struct list_head *head)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&timer->lock, flags);
+       while (!list_empty(head))
+               list_del_init(head->next);
+       spin_unlock_irqrestore(&timer->lock, flags);
+}
+
 /*
  * timer tasklet
  *
@@ -727,34 +785,15 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
 static void snd_timer_tasklet(unsigned long arg)
 {
        struct snd_timer *timer = (struct snd_timer *) arg;
-       struct snd_timer_instance *ti;
-       struct list_head *p;
-       unsigned long resolution, ticks;
        unsigned long flags;
 
-       if (timer->card && timer->card->shutdown)
+       if (timer->card && timer->card->shutdown) {
+               snd_timer_clear_callbacks(timer, &timer->sack_list_head);
                return;
+       }
 
        spin_lock_irqsave(&timer->lock, flags);
-       /* now process all callbacks */
-       while (!list_empty(&timer->sack_list_head)) {
-               p = timer->sack_list_head.next;         /* get first item */
-               ti = list_entry(p, struct snd_timer_instance, ack_list);
-
-               /* remove from ack_list and make empty */
-               list_del_init(p);
-
-               ticks = ti->pticks;
-               ti->pticks = 0;
-               resolution = ti->resolution;
-
-               ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
-               spin_unlock(&timer->lock);
-               if (ti->callback)
-                       ti->callback(ti, resolution, ticks);
-               spin_lock(&timer->lock);
-               ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
-       }
+       snd_timer_process_callbacks(timer, &timer->sack_list_head);
        spin_unlock_irqrestore(&timer->lock, flags);
 }
 
@@ -767,16 +806,18 @@ static void snd_timer_tasklet(unsigned long arg)
 void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
 {
        struct snd_timer_instance *ti, *ts, *tmp;
-       unsigned long resolution, ticks;
-       struct list_head *p, *ack_list_head;
+       unsigned long resolution;
+       struct list_head *ack_list_head;
        unsigned long flags;
        int use_tasklet = 0;
 
        if (timer == NULL)
                return;
 
-       if (timer->card && timer->card->shutdown)
+       if (timer->card && timer->card->shutdown) {
+               snd_timer_clear_callbacks(timer, &timer->ack_list_head);
                return;
+       }
 
        spin_lock_irqsave(&timer->lock, flags);
 
@@ -790,6 +831,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
         */
        list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
                                 active_list) {
+               if (ti->flags & SNDRV_TIMER_IFLG_DEAD)
+                       continue;
                if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
                        continue;
                ti->pticks += ticks_left;
@@ -839,23 +882,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
        }
 
        /* now process all fast callbacks */
-       while (!list_empty(&timer->ack_list_head)) {
-               p = timer->ack_list_head.next;          /* get first item */
-               ti = list_entry(p, struct snd_timer_instance, ack_list);
-
-               /* remove from ack_list and make empty */
-               list_del_init(p);
-
-               ticks = ti->pticks;
-               ti->pticks = 0;
-
-               ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
-               spin_unlock(&timer->lock);
-               if (ti->callback)
-                       ti->callback(ti, resolution, ticks);
-               spin_lock(&timer->lock);
-               ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
-       }
+       snd_timer_process_callbacks(timer, &timer->ack_list_head);
 
        /* do we have any slow callbacks? */
        use_tasklet = !list_empty(&timer->sack_list_head);
@@ -1882,7 +1909,10 @@ static int snd_timer_user_start(struct file *file)
        snd_timer_stop(tu->timeri);
        tu->timeri->lost = 0;
        tu->last_resolution = 0;
-       return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0;
+       err = snd_timer_start(tu->timeri, tu->ticks);
+       if (err < 0)
+               return err;
+       return 0;
 }
 
 static int snd_timer_user_stop(struct file *file)
@@ -1893,7 +1923,10 @@ static int snd_timer_user_stop(struct file *file)
        tu = file->private_data;
        if (!tu->timeri)
                return -EBADFD;
-       return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
+       err = snd_timer_stop(tu->timeri);
+       if (err < 0)
+               return err;
+       return 0;
 }
 
 static int snd_timer_user_continue(struct file *file)
@@ -1908,7 +1941,10 @@ static int snd_timer_user_continue(struct file *file)
        if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
                return snd_timer_user_start(file);
        tu->timeri->lost = 0;
-       return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
+       err = snd_timer_continue(tu->timeri);
+       if (err < 0)
+               return err;
+       return 0;
 }
 
 static int snd_timer_user_pause(struct file *file)
@@ -1919,7 +1955,10 @@ static int snd_timer_user_pause(struct file *file)
        tu = file->private_data;
        if (!tu->timeri)
                return -EBADFD;
-       return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
+       err = snd_timer_pause(tu->timeri);
+       if (err < 0)
+               return err;
+       return 0;
 }
 
 enum {
index 8c3fbe1..c14e57b 100644 (file)
@@ -337,7 +337,7 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
 
        loopback_timer_stop_sync(dpcm);
 
-       salign = (snd_pcm_format_width(runtime->format) *
+       salign = (snd_pcm_format_physical_width(runtime->format) *
                                                runtime->channels) / 8;
        bps = salign * runtime->rate;
        if (bps <= 0 || salign <= 0)
@@ -562,6 +562,8 @@ static const struct snd_pcm_hardware loopback_pcm_hardware =
                         SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
                         SNDRV_PCM_INFO_RESUME),
        .formats =      (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |
+                        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
                         SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
                         SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
        .rates =        SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
index 3ada55e..43f28b8 100644 (file)
@@ -56,8 +56,9 @@
 #define INTERRUPT_INTERVAL     16
 #define QUEUE_LENGTH           48
 
-#define IN_PACKET_HEADER_SIZE  4
+#define IR_HEADER_SIZE         8       // For header and timestamp.
 #define OUT_PACKET_HEADER_SIZE 0
+#define HEADER_TSTAMP_MASK     0x0000ffff
 
 static void pcm_period_tasklet(unsigned long data);
 
@@ -456,7 +457,7 @@ static inline int queue_out_packet(struct amdtp_stream *s,
 
 static inline int queue_in_packet(struct amdtp_stream *s)
 {
-       return queue_packet(s, IN_PACKET_HEADER_SIZE, s->max_payload_length);
+       return queue_packet(s, IR_HEADER_SIZE, s->max_payload_length);
 }
 
 static int handle_out_packet(struct amdtp_stream *s,
@@ -701,13 +702,6 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
        return cycle;
 }
 
-static inline u32 decrement_cycle_count(u32 cycle, unsigned int subtrahend)
-{
-       if (cycle < subtrahend)
-               cycle += 8 * CYCLES_PER_SECOND;
-       return cycle - subtrahend;
-}
-
 static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
                                size_t header_length, void *header,
                                void *private_data)
@@ -745,29 +739,26 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
        struct amdtp_stream *s = private_data;
        unsigned int i, packets;
        unsigned int payload_length, max_payload_length;
-       __be32 *headers = header;
-       u32 cycle;
+       __be32 *ctx_header = header;
 
        if (s->packet_index < 0)
                return;
 
        /* The number of packets in buffer */
-       packets = header_length / IN_PACKET_HEADER_SIZE;
-
-       cycle = compute_cycle_count(tstamp);
-
-       /* Align to actual cycle count for the last packet. */
-       cycle = decrement_cycle_count(cycle, packets);
+       packets = header_length / IR_HEADER_SIZE;
 
        /* For buffer-over-run prevention. */
        max_payload_length = s->max_payload_length;
 
        for (i = 0; i < packets; i++) {
-               cycle = increment_cycle_count(cycle, 1);
+               u32 iso_header = be32_to_cpu(ctx_header[0]);
+               unsigned int cycle;
+
+               tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
+               cycle = compute_cycle_count(tstamp);
 
                /* The number of bytes in this packet */
-               payload_length =
-                       (be32_to_cpu(headers[i]) >> ISO_DATA_LENGTH_SHIFT);
+               payload_length = iso_header >> ISO_DATA_LENGTH_SHIFT;
                if (payload_length > max_payload_length) {
                        dev_err(&s->unit->device,
                                "Detect jumbo payload: %04x %04x\n",
@@ -777,6 +768,8 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
 
                if (s->handle_packet(s, payload_length, cycle, i) < 0)
                        break;
+
+               ctx_header += IR_HEADER_SIZE / sizeof(__be32);
        }
 
        /* Queueing error or detecting invalid payload. */
@@ -797,6 +790,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
                                        void *header, void *private_data)
 {
        struct amdtp_stream *s = private_data;
+       __be32 *ctx_header = header;
        u32 cycle;
        unsigned int packets;
 
@@ -807,11 +801,10 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
        s->callbacked = true;
        wake_up(&s->callback_wait);
 
-       cycle = compute_cycle_count(tstamp);
-
        if (s->direction == AMDTP_IN_STREAM) {
-               packets = header_length / IN_PACKET_HEADER_SIZE;
-               cycle = decrement_cycle_count(cycle, packets);
+               tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
+               cycle = compute_cycle_count(tstamp);
+
                context->callback.sc = in_stream_callback;
                if (s->flags & CIP_NO_HEADER)
                        s->handle_packet = handle_in_packet_without_header;
@@ -819,6 +812,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
                        s->handle_packet = handle_in_packet;
        } else {
                packets = header_length / 4;
+               cycle = compute_cycle_count(tstamp);
                cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
                context->callback.sc = out_stream_callback;
                if (s->flags & CIP_NO_HEADER)
@@ -880,7 +874,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
        if (s->direction == AMDTP_IN_STREAM) {
                dir = DMA_FROM_DEVICE;
                type = FW_ISO_CONTEXT_RECEIVE;
-               header_size = IN_PACKET_HEADER_SIZE;
+               header_size = IR_HEADER_SIZE;
        } else {
                dir = DMA_TO_DEVICE;
                type = FW_ISO_CONTEXT_TRANSMIT;
index 6c9b743..cb0c967 100644 (file)
@@ -412,6 +412,12 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
                                 CIP_HEADER_WITHOUT_EOH;
                        fmt = CIP_FMT_MOTU_TX_V3;
                }
+
+               if (protocol == &snd_motu_protocol_v2) {
+                       // 8pre has some quirks.
+                       flags |= CIP_WRONG_DBS |
+                                CIP_SKIP_DBC_ZERO_CHECK;
+               }
        } else {
                process_data_blocks = process_rx_data_blocks;
                flags |= CIP_DBC_IS_END_EVENT;
index 453fc29..848fffe 100644 (file)
@@ -15,6 +15,8 @@
 #define  V2_CLOCK_SRC_SHIFT                    0
 #define  V2_CLOCK_TRAVELER_FETCH_DISABLE       0x04000000
 #define  V2_CLOCK_TRAVELER_FETCH_ENABLE                0x03000000
+#define  V2_CLOCK_8PRE_FETCH_DISABLE           0x02000000
+#define  V2_CLOCK_8PRE_FETCH_ENABLE            0x00000000
 
 #define V2_IN_OUT_CONF_OFFSET                  0x0c04
 #define  V2_OPT_OUT_IFACE_MASK                 0x00000c00
@@ -132,20 +134,31 @@ static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable)
        u32 data;
        int err = 0;
 
-       if (motu->spec == &snd_motu_spec_traveler) {
+       if (motu->spec == &snd_motu_spec_traveler ||
+           motu->spec == &snd_motu_spec_8pre) {
                err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
                                                &reg, sizeof(reg));
                if (err < 0)
                        return err;
                data = be32_to_cpu(reg);
 
-               data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE |
-                         V2_CLOCK_TRAVELER_FETCH_ENABLE);
-
-               if (enable)
-                       data |= V2_CLOCK_TRAVELER_FETCH_ENABLE;
-               else
-                       data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
+               if (motu->spec == &snd_motu_spec_traveler) {
+                       data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE |
+                                 V2_CLOCK_TRAVELER_FETCH_ENABLE);
+
+                       if (enable)
+                               data |= V2_CLOCK_TRAVELER_FETCH_ENABLE;
+                       else
+                               data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
+               } else if (motu->spec == &snd_motu_spec_8pre) {
+                       data &= ~(V2_CLOCK_8PRE_FETCH_DISABLE |
+                                 V2_CLOCK_8PRE_FETCH_ENABLE);
+
+                       if (enable)
+                               data |= V2_CLOCK_8PRE_FETCH_DISABLE;
+                       else
+                               data |= V2_CLOCK_8PRE_FETCH_ENABLE;
+               }
 
                reg = cpu_to_be32(data);
                err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
@@ -220,10 +233,16 @@ static void calculate_differed_part(struct snd_motu_packet_format *formats,
         * interfaces.
         */
        data = (data & mask) >> shift;
-       if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) &&
-           data == V2_OPT_IFACE_MODE_ADAT) {
-               pcm_chunks[0] += 8;
-               pcm_chunks[1] += 4;
+       if (data == V2_OPT_IFACE_MODE_ADAT) {
+               if (flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) {
+                       pcm_chunks[0] += 8;
+                       pcm_chunks[1] += 4;
+               }
+               // 8pre has two sets of optical interface and doesn't reduce
+               // chunks for ADAT signals.
+               if (flags & SND_MOTU_SPEC_HAS_OPT_IFACE_B) {
+                       pcm_chunks[1] += 4;
+               }
        }
 
        /* At mode x4, no data chunks are supported in this part. */
index 513291b..201539d 100644 (file)
@@ -203,6 +203,20 @@ const struct snd_motu_spec snd_motu_spec_traveler = {
        .analog_out_ports = 8,
 };
 
+const struct snd_motu_spec snd_motu_spec_8pre = {
+       .name = "8pre",
+       .protocol = &snd_motu_protocol_v2,
+       // In tx, use coax chunks for mix-return 1/2. In rx, use coax chunks for
+       // dummy 1/2.
+       .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
+                SND_MOTU_SPEC_HAS_OPT_IFACE_A |
+                SND_MOTU_SPEC_HAS_OPT_IFACE_B |
+                SND_MOTU_SPEC_RX_MIDI_2ND_Q |
+                SND_MOTU_SPEC_TX_MIDI_2ND_Q,
+       .analog_in_ports = 8,
+       .analog_out_ports = 2,
+};
+
 static const struct snd_motu_spec motu_828mk3 = {
        .name = "828mk3",
        .protocol = &snd_motu_protocol_v3,
@@ -248,6 +262,7 @@ static const struct snd_motu_spec motu_audio_express = {
 static const struct ieee1394_device_id motu_id_table[] = {
        SND_MOTU_DEV_ENTRY(0x000003, &motu_828mk2),
        SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler),
+       SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre),
        SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3),     /* FireWire only. */
        SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3),     /* Hybrid. */
        SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express),
index fd5327d..1cd112b 100644 (file)
@@ -130,6 +130,7 @@ extern const struct snd_motu_protocol snd_motu_protocol_v2;
 extern const struct snd_motu_protocol snd_motu_protocol_v3;
 
 extern const struct snd_motu_spec snd_motu_spec_traveler;
+extern const struct snd_motu_spec snd_motu_spec_8pre;
 
 int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
                    enum amdtp_stream_direction dir,
index ec7715c..c203af7 100644 (file)
@@ -104,9 +104,7 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
                return ret;
 
        bus->ext_ops = ext_ops;
-       INIT_LIST_HEAD(&bus->hlink_list);
        bus->idx = idx++;
-
        bus->cmd_dma_state = true;
 
        return 0;
index ad8eee0..10e5d26 100644 (file)
@@ -39,6 +39,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
        spin_lock_init(&bus->reg_lock);
        mutex_init(&bus->cmd_mutex);
        mutex_init(&bus->lock);
+       INIT_LIST_HEAD(&bus->hlink_list);
        bus->irq = -1;
        return 0;
 }
index 4ac76f4..d708ae1 100644 (file)
@@ -306,7 +306,7 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry,
        used = 0;
        for (block = alloc->first, i = 0; block; block = block->next, i++) {
                used += block->size;
-               snd_iprintf(buffer, "Block %i at 0x%lx onboard 0x%x size %i (0x%x):\n", i, (long) block, block->ptr, block->size, block->size);
+               snd_iprintf(buffer, "Block %i onboard 0x%x size %i (0x%x):\n", i, block->ptr, block->size, block->size);
                if (block->share ||
                    block->share_id[0] || block->share_id[1] ||
                    block->share_id[2] || block->share_id[3])
index 43f2228..4f5a624 100644 (file)
 
 static int __init alsa_sound_last_init(void)
 {
+       struct snd_card *card;
        int idx, ok = 0;
        
        printk(KERN_INFO "ALSA device list:\n");
-       for (idx = 0; idx < SNDRV_CARDS; idx++)
-               if (snd_cards[idx] != NULL) {
-                       printk(KERN_INFO "  #%i: %s\n", idx, snd_cards[idx]->longname);
+       for (idx = 0; idx < SNDRV_CARDS; idx++) {
+               card = snd_card_ref(idx);
+               if (card) {
+                       printk(KERN_INFO "  #%i: %s\n", idx, card->longname);
+                       snd_card_unref(card);
                        ok++;
                }
+       }
        if (ok == 0)
                printk(KERN_INFO "  No soundcards found.\n");
        return 0;
index 61f85ff..0419c75 100644 (file)
@@ -1882,22 +1882,8 @@ int snd_emu10k1_create(struct snd_card *card,
                        c->name, pci->vendor, pci->device,
                        emu->serial);
 
-       if (!*card->id && c->id) {
-               int i, n = 0;
+       if (!*card->id && c->id)
                strlcpy(card->id, c->id, sizeof(card->id));
-               for (;;) {
-                       for (i = 0; i < snd_ecards_limit; i++) {
-                               if (snd_cards[i] && !strcmp(snd_cards[i]->id, card->id))
-                                       break;
-                       }
-                       if (i >= snd_ecards_limit)
-                               break;
-                       n++;
-                       if (n >= SNDRV_CARDS)
-                               break;
-                       snprintf(card->id, sizeof(card->id), "%s_%d", c->id, n);
-               }
-       }
 
        is_audigy = emu->audigy = c->emu10k2_chip;
 
index 701a69d..b20eb7f 100644 (file)
@@ -832,7 +832,13 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
        struct hda_codec *codec = device->device_data;
 
        codec->in_freeing = 1;
-       snd_hdac_device_unregister(&codec->core);
+       /*
+        * snd_hda_codec_device_new() is used by legacy HDA and ASoC driver.
+        * We can't unregister ASoC device since it will be unregistered in
+        * snd_hdac_ext_bus_device_remove().
+        */
+       if (codec->core.type == HDA_DEV_LEGACY)
+               snd_hdac_device_unregister(&codec->core);
        codec_display_power(codec, false);
        put_device(hda_codec_dev(codec));
        return 0;
index 2ec9108..789308f 100644 (file)
@@ -1788,9 +1788,6 @@ static int azx_first_init(struct azx *chip)
                        chip->msi = 0;
        }
 
-       if (azx_acquire_irq(chip, 0) < 0)
-               return -EBUSY;
-
        pci_set_master(pci);
        synchronize_irq(bus->irq);
 
@@ -1904,6 +1901,9 @@ static int azx_first_init(struct azx *chip)
                return -ENODEV;
        }
 
+       if (azx_acquire_irq(chip, 0) < 0)
+               return -EBUSY;
+
        strcpy(card->driver, "HDA-Intel");
        strlcpy(card->shortname, driver_short_names[chip->driver_type],
                sizeof(card->shortname));
index 42cd394..d743f2b 100644 (file)
@@ -803,11 +803,10 @@ static int alc_init(struct hda_codec *codec)
        if (spec->init_hook)
                spec->init_hook(codec);
 
+       snd_hda_gen_init(codec);
        alc_fix_pll(codec);
        alc_auto_init_amp(codec, spec->init_amp);
 
-       snd_hda_gen_init(codec);
-
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
 
        return 0;
index 521236e..f77a0d5 100644 (file)
@@ -233,7 +233,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
        int fill_stages, dma_ch, stage;
        enum snd_ps3_ch ch;
        uint32_t ch0_kick_event = 0; /* initialize to mute gcc */
-       void *start_vaddr;
        unsigned long irqsave;
        int silent = 0;
 
@@ -257,7 +256,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
        fill_stages = 4;
        spin_lock_irqsave(&card->dma_lock, irqsave);
        for (ch = 0; ch < 2; ch++) {
-               start_vaddr = card->dma_next_transfer_vaddr[0];
                for (stage = 0; stage < fill_stages; stage++) {
                        dma_ch = stage * 2 + ch;
                        if (silent)
@@ -526,9 +524,7 @@ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
-       int pcm_index;
 
-       pcm_index = substream->pcm->device;
        /* to retrieve substream/runtime in interrupt handler */
        card->substream = substream;
 
index f889d94..7d49402 100644 (file)
@@ -328,6 +328,12 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
                dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
                goto error_no_pm;
        }
+       /*
+        * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver
+        * hda_codec.c will check this flag to determine if unregister
+        * device is needed.
+        */
+       hdev->type = HDA_DEV_ASOC;
 
        /*
         * snd_hda_codec_device_new decrements the usage count so call get pm
index d9fcae0..fae48d1 100644 (file)
@@ -39,6 +39,11 @@ snd_emux_hwdep_load_patch(struct snd_emux *emu, void __user *arg)
        if (copy_from_user(&patch, arg, sizeof(patch)))
                return -EFAULT;
 
+       if (patch.key == GUS_PATCH)
+               return snd_soundfont_load_guspatch(emu->sflist, arg,
+                                                  patch.len + sizeof(patch),
+                                                  TMP_CLIENT_ID);
+
        if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
            patch.type <= SNDRV_SFNT_PROBE_DATA) {
                err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID);
index 31a4ea9..9b5d701 100644 (file)
@@ -856,6 +856,8 @@ calc_gus_envelope_time(int rate, int start, int end)
        int r, p, t;
        r = (3 - ((rate >> 6) & 3)) * 3;
        p = rate & 0x3f;
+       if (!p)
+               p = 1;
        t = end - start;
        if (t < 0) t = -t;
        if (13 > r)
index 73d7dff..e003b5e 100644 (file)
@@ -2675,6 +2675,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
        kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
        if (! kctl) {
                usb_audio_err(state->chip, "cannot malloc kcontrol\n");
+               for (i = 0; i < desc->bNrInPins; i++)
+                       kfree(namelist[i]);
                kfree(namelist);
                kfree(cval);
                return -ENOMEM;
@@ -3490,7 +3492,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
        if (err < 0)
                goto _error;
 
-       snd_usb_mixer_apply_create_quirk(mixer);
+       err = snd_usb_mixer_apply_create_quirk(mixer);
+       if (err < 0)
+               goto _error;
 
        err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops);
        if (err < 0)
index 86e8091..629b845 100644 (file)
@@ -2770,6 +2770,90 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_NOVATION
        }
 },
+{
+       /*
+        * Focusrite Scarlett Solo 2nd generation
+        * Reports that playback should use Synch: Synchronous
+        * while still providing a feedback endpoint. Synchronous causes
+        * snapping on some sample rates.
+        * Force it to use Synch: Asynchronous.
+        */
+       USB_DEVICE(0x1235, 0x8205),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = 0,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .protocol = UAC_VERSION_2,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000 |
+                                                SNDRV_PCM_RATE_176400 |
+                                                SNDRV_PCM_RATE_192000,
+                                       .rate_min = 44100,
+                                       .rate_max = 192000,
+                                       .nr_rates = 6,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000, 88200,
+                                               96000, 176400, 192000
+                                       },
+                                       .clock = 41
+                               }
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = 0,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .protocol = UAC_VERSION_2,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000 |
+                                                SNDRV_PCM_RATE_176400 |
+                                                SNDRV_PCM_RATE_192000,
+                                       .rate_min = 44100,
+                                       .rate_max = 192000,
+                                       .nr_rates = 6,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000, 88200,
+                                               96000, 176400, 192000
+                                       },
+                                       .clock = 41
+                               }
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Access Music devices */
 {
index c1dd9a7..bfe1108 100644 (file)
@@ -75,7 +75,8 @@ static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct v
 
        if (!us428->us428ctls_sharedmem) {
                init_waitqueue_head(&us428->us428ctls_wait_queue_head);
-               if(!(us428->us428ctls_sharedmem = snd_malloc_pages(sizeof(struct us428ctls_sharedmem), GFP_KERNEL)))
+               us428->us428ctls_sharedmem = alloc_pages_exact(sizeof(struct us428ctls_sharedmem), GFP_KERNEL);
+               if (!us428->us428ctls_sharedmem)
                        return -ENOMEM;
                memset(us428->us428ctls_sharedmem, -1, sizeof(struct us428ctls_sharedmem));
                us428->us428ctls_sharedmem->CtlSnapShotLast = -2;
index 221adf6..51d7311 100644 (file)
@@ -155,9 +155,9 @@ void usb_stream_free(struct usb_stream_kernel *sk)
        if (!s)
                return;
 
-       free_pages((unsigned long)sk->write_page, get_order(s->write_size));
+       free_pages_exact(sk->write_page, s->write_size);
        sk->write_page = NULL;
-       free_pages((unsigned long)s, get_order(s->read_size));
+       free_pages_exact(s, s->read_size);
        sk->s = NULL;
 }
 
@@ -172,7 +172,6 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
        int read_size = sizeof(struct usb_stream);
        int write_size;
        int usb_frames = dev->speed == USB_SPEED_HIGH ? 8000 : 1000;
-       int pg;
 
        in_pipe = usb_rcvisocpipe(dev, in_endpoint);
        out_pipe = usb_sndisocpipe(dev, out_endpoint);
@@ -202,11 +201,10 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
                goto out;
        }
 
-       pg = get_order(read_size);
-       sk->s = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO|
-                                         __GFP_NOWARN, pg);
+       sk->s = alloc_pages_exact(read_size,
+                                 GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
        if (!sk->s) {
-               snd_printk(KERN_WARNING "couldn't __get_free_pages()\n");
+               pr_warn("us122l: couldn't allocate read buffer\n");
                goto out;
        }
        sk->s->cfg.version = USB_STREAM_INTERFACE_VERSION;
@@ -221,13 +219,11 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
        sk->s->period_size = frame_size * period_frames;
 
        sk->s->write_size = write_size;
-       pg = get_order(write_size);
 
-       sk->write_page =
-               (void *)__get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO|
-                                        __GFP_NOWARN, pg);
+       sk->write_page = alloc_pages_exact(write_size,
+                                          GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
        if (!sk->write_page) {
-               snd_printk(KERN_WARNING "couldn't __get_free_pages()\n");
+               pr_warn("us122l: couldn't allocate write buffer\n");
                usb_stream_free(sk);
                return NULL;
        }
index da4a5a5..e8687b3 100644 (file)
@@ -293,10 +293,8 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y)
        if (! (usX2Y->In04urb = usb_alloc_urb(0, GFP_KERNEL)))
                return -ENOMEM;
 
-       if (! (usX2Y->In04Buf = kmalloc(21, GFP_KERNEL))) {
-               usb_free_urb(usX2Y->In04urb);
+       if (! (usX2Y->In04Buf = kmalloc(21, GFP_KERNEL)))
                return -ENOMEM;
-       }
         
        init_waitqueue_head(&usX2Y->In04WaitQueue);
        usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4),
@@ -437,7 +435,8 @@ static void snd_usX2Y_card_private_free(struct snd_card *card)
        kfree(usX2Y(card)->In04Buf);
        usb_free_urb(usX2Y(card)->In04urb);
        if (usX2Y(card)->us428ctls_sharedmem)
-               snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem));
+               free_pages_exact(usX2Y(card)->us428ctls_sharedmem,
+                                sizeof(*usX2Y(card)->us428ctls_sharedmem));
        if (usX2Y(card)->card_index >= 0  &&  usX2Y(card)->card_index < SNDRV_CARDS)
                snd_usX2Y_card_used[usX2Y(card)->card_index] = 0;
 }
index 714cf50..ace8185 100644 (file)
@@ -488,7 +488,9 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
        snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
 
        if (NULL == usX2Y->hwdep_pcm_shm) {
-               if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
+               usX2Y->hwdep_pcm_shm = alloc_pages_exact(sizeof(struct snd_usX2Y_hwdep_pcm_shm),
+                                                        GFP_KERNEL);
+               if (!usX2Y->hwdep_pcm_shm)
                        return -ENOMEM;
                memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
        }
@@ -700,7 +702,7 @@ static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
 {
        struct usX2Ydev *usX2Y = hwdep->private_data;
        if (NULL != usX2Y->hwdep_pcm_shm)
-               snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
+               free_pages_exact(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
 }