Merge branch 'for-linus' into for-next
authorTakashi Iwai <tiwai@suse.de>
Mon, 6 May 2019 13:07:50 +0000 (15:07 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 6 May 2019 13:07:57 +0000 (15:07 +0200)
Signed-off-by: Takashi Iwai <tiwai@suse.de>
44 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/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 e17ebf7..d373d97 100644 (file)
@@ -3351,7 +3351,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
@@ -3404,7 +3404,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/
 
@@ -5696,7 +5696,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
 
@@ -6036,7 +6036,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/
 
@@ -11593,7 +11593,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/
 
@@ -14490,7 +14490,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/
@@ -16100,7 +16099,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 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));
 }