diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/memalloc.c | 53 | ||||
-rw-r--r-- | sound/core/pcm.c | 14 | ||||
-rw-r--r-- | sound/core/seq/oss/seq_oss_device.h | 10 | ||||
-rw-r--r-- | sound/core/seq/oss/seq_oss_rw.c | 11 | ||||
-rw-r--r-- | sound/core/seq/oss/seq_oss_writeq.c | 2 | ||||
-rw-r--r-- | sound/core/seq/seq_clientmgr.c | 104 | ||||
-rw-r--r-- | sound/core/seq/seq_clientmgr.h | 8 | ||||
-rw-r--r-- | sound/core/seq/seq_fifo.c | 14 | ||||
-rw-r--r-- | sound/core/seq/seq_memory.c | 30 | ||||
-rw-r--r-- | sound/core/seq/seq_ports.c | 30 | ||||
-rw-r--r-- | sound/core/seq/seq_ports.h | 5 | ||||
-rw-r--r-- | sound/core/timer.c | 181 | ||||
-rw-r--r-- | sound/drivers/aloop.c | 4 | ||||
-rw-r--r-- | sound/firewire/amdtp-stream.c | 44 | ||||
-rw-r--r-- | sound/firewire/motu/amdtp-motu.c | 6 | ||||
-rw-r--r-- | sound/firewire/motu/motu-protocol-v2.c | 43 | ||||
-rw-r--r-- | sound/firewire/motu/motu.c | 15 | ||||
-rw-r--r-- | sound/firewire/motu/motu.h | 1 | ||||
-rw-r--r-- | sound/synth/emux/emux_hwdep.c | 5 | ||||
-rw-r--r-- | sound/usb/usx2y/usX2Yhwdep.c | 3 | ||||
-rw-r--r-- | sound/usb/usx2y/usb_stream.c | 20 | ||||
-rw-r--r-- | sound/usb/usx2y/usbusx2y.c | 3 | ||||
-rw-r--r-- | sound/usb/usx2y/usx2yhwdeppcm.c | 6 |
23 files changed, 324 insertions, 288 deletions
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/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..3acd80e718f2 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -179,6 +179,36 @@ 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); + 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); + snd_use_lock_free(&client->use_lock); + 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 +233,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 +253,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 +261,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 +280,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 +1927,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 +2248,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 +2277,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/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/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/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..9f7bbed2c0f0 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -437,7 +437,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)); } |