diff options
Diffstat (limited to 'sound')
39 files changed, 485 insertions, 330 deletions
diff --git a/sound/core/init.c b/sound/core/init.c index 079c12d64b0e..d64416f0a281 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -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) { diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index eb974235c92b..9f48e1d3a257 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -32,53 +32,6 @@ /* * - * 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 diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 64d904bee8bb..c8618678649c 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -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); + } } } diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 7b63aee124af..998e477522fd 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -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 */ diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index 2d0e9eaf13aa..77eb1fe1155c 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -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 */ diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c index 30886f5fb100..eb1ef12181f3 100644 --- a/sound/core/seq/oss/seq_oss_rw.c +++ b/sound/core/seq/oss/seq_oss_rw.c @@ -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; } diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 5e04f4df10e4..b2f69617591f 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -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); diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 38e7deab6384..c0227a672442 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -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. diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index 0611e1e0ed5b..28a51dcc0190 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -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 diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 72c0302a55d2..97ee89cb6426 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -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); diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 5b0388202bac..19b718e871c5 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -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; } diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 24d90abfc64d..ac7556ab531c 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -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; } /* diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h index 26bd71f36c41..06003b36652e 100644 --- a/sound/core/seq/seq_ports.h +++ b/sound/core/seq/seq_ports.h @@ -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 diff --git a/sound/core/sound.c b/sound/core/sound.c index b30f027eb0fe..a9ad4379523b 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -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); diff --git a/sound/core/timer.c b/sound/core/timer.c index 61a0cec6e1f6..d23efec35660 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -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(®ister_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(®ister_mutex); timeri = snd_timer_instance_new(owner, NULL); if (!timeri) { - mutex_unlock(®ister_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(®ister_mutex); - *ti = timeri; - return err; + goto unlock; } /* open a master instance */ - mutex_lock(®ister_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(®ister_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(®ister_mutex); - return -EBUSY; + err = -EBUSY; + timeri = NULL; + goto unlock; } } if (timer->num_instances >= timer->max_instances) { - mutex_unlock(®ister_mutex); - return -EBUSY; + err = -EBUSY; + goto unlock; } timeri = snd_timer_instance_new(owner, timer); if (!timeri) { - mutex_unlock(®ister_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(®ister_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(®ister_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 { diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 8c3fbe1276be..c14e57b2a135 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -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, diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 3ada55ed5381..43f28b813386 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -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; diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 6c9b743ea74b..cb0c967dea63 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -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; diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c index 453fc29fade7..848fffe7387e 100644 --- a/sound/firewire/motu/motu-protocol-v2.c +++ b/sound/firewire/motu/motu-protocol-v2.c @@ -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, ®, 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. */ diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 513291ba0ab0..201539d4488c 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -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), diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index fd5327d30ab1..1cd112be7dad 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -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, diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index ec7715c6b0c0..c203af71a099 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -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; diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index ad8eee08013f..10e5d261fde1 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -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; } diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index 4ac76f46dd76..d708ae1525e4 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -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]) diff --git a/sound/last.c b/sound/last.c index 43f222825038..4f5a624ab438 100644 --- a/sound/last.c +++ b/sound/last.c @@ -24,14 +24,18 @@ 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; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 61f85ff91cd9..0419c75bdf5a 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -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; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 701a69d856f5..b20eb7fc83eb 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -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; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2ec91085fa3e..789308f54785 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -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)); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 42cd3945e0de..d743f2b0e3cf 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -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; diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 521236efcc4d..f77a0d5c0385 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -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; diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index f889d94c8e3c..7d4940256914 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -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 diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index d9fcae071b47..fae48d108b97 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c @@ -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); diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 31a4ea94830e..9b5d70104489 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -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) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 73d7dff425c1..e003b5e7b01a 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -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) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 86e80916a029..629b84532648 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -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 */ { diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index c1dd9a7b48df..bfe1108416cf 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -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; diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index 221adf68bd0c..51d73111263a 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -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; } diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index da4a5a541512..e8687b3bd3c8 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -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; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 714cf50d4a4c..ace8185c3f6d 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -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)); } |