diff options
Diffstat (limited to 'kernel/sound/core/seq')
-rw-r--r-- | kernel/sound/core/seq/Makefile | 3 | ||||
-rw-r--r-- | kernel/sound/core/seq/oss/seq_oss.c | 8 | ||||
-rw-r--r-- | kernel/sound/core/seq/oss/seq_oss_device.h | 1 | ||||
-rw-r--r-- | kernel/sound/core/seq/oss/seq_oss_init.c | 23 | ||||
-rw-r--r-- | kernel/sound/core/seq/oss/seq_oss_midi.c | 4 | ||||
-rw-r--r-- | kernel/sound/core/seq/oss/seq_oss_readq.c | 10 | ||||
-rw-r--r-- | kernel/sound/core/seq/oss/seq_oss_synth.c | 6 | ||||
-rw-r--r-- | kernel/sound/core/seq/oss/seq_oss_writeq.c | 4 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_clientmgr.c | 9 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_compat.c | 9 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_device.c | 6 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_info.c | 19 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_info.h | 2 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_memory.c | 13 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_ports.c | 236 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_queue.c | 6 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_timer.c | 91 | ||||
-rw-r--r-- | kernel/sound/core/seq/seq_virmidi.c | 23 |
18 files changed, 279 insertions, 194 deletions
diff --git a/kernel/sound/core/seq/Makefile b/kernel/sound/core/seq/Makefile index 941f64a85..b65fa5a19 100644 --- a/kernel/sound/core/seq/Makefile +++ b/kernel/sound/core/seq/Makefile @@ -6,7 +6,8 @@ snd-seq-device-objs := seq_device.o snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \ seq_fifo.o seq_prioq.o seq_timer.o \ - seq_system.o seq_ports.o seq_info.o + seq_system.o seq_ports.o +snd-seq-$(CONFIG_SND_PROC_FS) += seq_info.o snd-seq-midi-objs := seq_midi.o snd-seq-midi-emul-objs := seq_midi_emul.o snd-seq-midi-event-objs := seq_midi_event.o diff --git a/kernel/sound/core/seq/oss/seq_oss.c b/kernel/sound/core/seq/oss/seq_oss.c index 72873a46a..cb2389910 100644 --- a/kernel/sound/core/seq/oss/seq_oss.c +++ b/kernel/sound/core/seq/oss/seq_oss.c @@ -45,7 +45,7 @@ MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC); */ static int register_device(void); static void unregister_device(void); -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS static int register_proc(void); static void unregister_proc(void); #else @@ -148,8 +148,6 @@ odev_release(struct inode *inode, struct file *file) if ((dp = file->private_data) == NULL) return 0; - snd_seq_oss_drain_write(dp); - mutex_lock(®ister_mutex); snd_seq_oss_release(dp); mutex_unlock(®ister_mutex); @@ -261,7 +259,7 @@ unregister_device(void) * /proc interface */ -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS static struct snd_info_entry *info_entry; @@ -303,4 +301,4 @@ unregister_proc(void) snd_info_free_entry(info_entry); info_entry = NULL; } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ diff --git a/kernel/sound/core/seq/oss/seq_oss_device.h b/kernel/sound/core/seq/oss/seq_oss_device.h index b43924325..d7b4d016b 100644 --- a/kernel/sound/core/seq/oss/seq_oss_device.h +++ b/kernel/sound/core/seq/oss/seq_oss_device.h @@ -127,7 +127,6 @@ int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int co unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait); void snd_seq_oss_reset(struct seq_oss_devinfo *dp); -void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp); /* */ void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time); diff --git a/kernel/sound/core/seq/oss/seq_oss_init.c b/kernel/sound/core/seq/oss/seq_oss_init.c index 2de3feff7..92c96a95a 100644 --- a/kernel/sound/core/seq/oss/seq_oss_init.c +++ b/kernel/sound/core/seq/oss/seq_oss_init.c @@ -202,7 +202,7 @@ snd_seq_oss_open(struct file *file, int level) dp->index = i; if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { - pr_err("ALSA: seq_oss: too many applications\n"); + pr_debug("ALSA: seq_oss: too many applications\n"); rc = -ENOMEM; goto _error; } @@ -436,22 +436,6 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp) /* - * Wait until the queue is empty (if we don't have nonblock) - */ -void -snd_seq_oss_drain_write(struct seq_oss_devinfo *dp) -{ - if (! dp->timer->running) - return; - if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) && - dp->writeq) { - while (snd_seq_oss_writeq_sync(dp->writeq)) - ; - } -} - - -/* * reset sequencer devices */ void @@ -479,8 +463,7 @@ snd_seq_oss_reset(struct seq_oss_devinfo *dp) snd_seq_oss_timer_stop(dp->timer); } - -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* * misc. functions for proc interface */ @@ -531,4 +514,4 @@ snd_seq_oss_system_info_read(struct snd_info_buffer *buf) snd_seq_oss_readq_info_read(dp->readq, buf); } } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ diff --git a/kernel/sound/core/seq/oss/seq_oss_midi.c b/kernel/sound/core/seq/oss/seq_oss_midi.c index 96e8395ae..aaff9ee32 100644 --- a/kernel/sound/core/seq/oss/seq_oss_midi.c +++ b/kernel/sound/core/seq/oss/seq_oss_midi.c @@ -665,7 +665,7 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* * proc interface */ @@ -705,4 +705,4 @@ snd_seq_oss_midi_info_read(struct snd_info_buffer *buf) snd_use_lock_free(&mdev->use_lock); } } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ diff --git a/kernel/sound/core/seq/oss/seq_oss_readq.c b/kernel/sound/core/seq/oss/seq_oss_readq.c index c080c73ce..046cb586f 100644 --- a/kernel/sound/core/seq/oss/seq_oss_readq.c +++ b/kernel/sound/core/seq/oss/seq_oss_readq.c @@ -91,8 +91,7 @@ snd_seq_oss_readq_clear(struct seq_oss_readq *q) q->head = q->tail = 0; } /* if someone sleeping, wake'em up */ - if (waitqueue_active(&q->midi_sleep)) - wake_up(&q->midi_sleep); + wake_up(&q->midi_sleep); q->input_time = (unsigned long)-1; } @@ -138,8 +137,7 @@ snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev) q->qlen++; /* wake up sleeper */ - if (waitqueue_active(&q->midi_sleep)) - wake_up(&q->midi_sleep); + wake_up(&q->midi_sleep); spin_unlock_irqrestore(&q->lock, flags); @@ -222,7 +220,7 @@ snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* * proc interface */ @@ -233,4 +231,4 @@ snd_seq_oss_readq_info_read(struct seq_oss_readq *q, struct snd_info_buffer *buf (waitqueue_active(&q->midi_sleep) ? "sleeping":"running"), q->qlen, q->input_time); } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ diff --git a/kernel/sound/core/seq/oss/seq_oss_synth.c b/kernel/sound/core/seq/oss/seq_oss_synth.c index 48e4fe1b6..b16dbef04 100644 --- a/kernel/sound/core/seq/oss/seq_oss_synth.c +++ b/kernel/sound/core/seq/oss/seq_oss_synth.c @@ -308,7 +308,7 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; - if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) + if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) return; for (i = 0; i < dp->max_synthdev; i++) { info = &dp->synths[i]; @@ -630,7 +630,7 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* * proc interface */ @@ -658,4 +658,4 @@ snd_seq_oss_synth_info_read(struct snd_info_buffer *buf) snd_use_lock_free(&rec->use_lock); } } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ diff --git a/kernel/sound/core/seq/oss/seq_oss_writeq.c b/kernel/sound/core/seq/oss/seq_oss_writeq.c index d50338bbc..1f6788a18 100644 --- a/kernel/sound/core/seq/oss/seq_oss_writeq.c +++ b/kernel/sound/core/seq/oss/seq_oss_writeq.c @@ -138,9 +138,7 @@ snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time) spin_lock_irqsave(&q->sync_lock, flags); q->sync_time = time; q->sync_event_put = 0; - if (waitqueue_active(&q->sync_sleep)) { - wake_up(&q->sync_sleep); - } + wake_up(&q->sync_sleep); spin_unlock_irqrestore(&q->sync_lock, flags); } diff --git a/kernel/sound/core/seq/seq_clientmgr.c b/kernel/sound/core/seq/seq_clientmgr.c index edbdab85f..58e79e02f 100644 --- a/kernel/sound/core/seq/seq_clientmgr.c +++ b/kernel/sound/core/seq/seq_clientmgr.c @@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct snd_seq_client *client, else down_read(&grp->list_mutex); list_for_each_entry(subs, &grp->list_head, src_list) { + /* both ports ready? */ + if (atomic_read(&subs->ref_count) != 2) + continue; event->dest = subs->info.dest; if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) /* convert time according to flag with subscription */ @@ -1962,7 +1965,7 @@ static int snd_seq_ioctl_remove_events(struct snd_seq_client *client, * No restrictions so for a user client we can clear * the whole fifo */ - if (client->type == USER_CLIENT) + if (client->type == USER_CLIENT && client->data.user.fifo) snd_seq_fifo_clear(client->data.user.fifo); } @@ -2447,7 +2450,7 @@ EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); /*---------------------------------------------------------------------------*/ -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* * /proc interface */ @@ -2549,7 +2552,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, snd_seq_client_unlock(client); } } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ /*---------------------------------------------------------------------------*/ diff --git a/kernel/sound/core/seq/seq_compat.c b/kernel/sound/core/seq/seq_compat.c index 81f7c109d..65175902a 100644 --- a/kernel/sound/core/seq/seq_compat.c +++ b/kernel/sound/core/seq/seq_compat.c @@ -49,11 +49,12 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned struct snd_seq_port_info *data; mm_segment_t fs; - data = memdup_user(data32, sizeof(*data32)); - if (IS_ERR(data)) - return PTR_ERR(data); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; - if (get_user(data->flags, &data32->flags) || + if (copy_from_user(data, data32, sizeof(*data32)) || + get_user(data->flags, &data32->flags) || get_user(data->time_queue, &data32->time_queue)) goto error; data->kernel = NULL; diff --git a/kernel/sound/core/seq/seq_device.c b/kernel/sound/core/seq/seq_device.c index d99f99d61..c4acf17e9 100644 --- a/kernel/sound/core/seq/seq_device.c +++ b/kernel/sound/core/seq/seq_device.c @@ -72,7 +72,7 @@ static struct bus_type snd_seq_bus_type = { /* * proc interface -- just for compatibility */ -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS static struct snd_info_entry *info_entry; static int print_dev_info(struct device *dev, void *data) @@ -272,7 +272,7 @@ EXPORT_SYMBOL_GPL(snd_seq_driver_unregister); static int __init seq_dev_proc_init(void) { -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", snd_seq_root); if (info_entry == NULL) @@ -305,7 +305,7 @@ static void __exit alsa_seq_device_exit(void) #ifdef CONFIG_MODULES cancel_work_sync(&autoload_work); #endif -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS snd_info_free_entry(info_entry); #endif bus_unregister(&snd_seq_bus_type); diff --git a/kernel/sound/core/seq/seq_info.c b/kernel/sound/core/seq/seq_info.c index acf776941..97015447b 100644 --- a/kernel/sound/core/seq/seq_info.c +++ b/kernel/sound/core/seq/seq_info.c @@ -27,7 +27,6 @@ #include "seq_clientmgr.h" #include "seq_timer.h" -#ifdef CONFIG_PROC_FS static struct snd_info_entry *queues_entry; static struct snd_info_entry *clients_entry; static struct snd_info_entry *timer_entry; @@ -51,6 +50,13 @@ create_info_entry(char *name, void (*read)(struct snd_info_entry *, return entry; } +static void free_info_entries(void) +{ + snd_info_free_entry(queues_entry); + snd_info_free_entry(clients_entry); + snd_info_free_entry(timer_entry); +} + /* create all our /proc entries */ int __init snd_seq_info_init(void) { @@ -59,14 +65,17 @@ int __init snd_seq_info_init(void) clients_entry = create_info_entry("clients", snd_seq_info_clients_read); timer_entry = create_info_entry("timer", snd_seq_info_timer_read); + if (!queues_entry || !clients_entry || !timer_entry) + goto error; return 0; + + error: + free_info_entries(); + return -ENOMEM; } int __exit snd_seq_info_done(void) { - snd_info_free_entry(queues_entry); - snd_info_free_entry(clients_entry); - snd_info_free_entry(timer_entry); + free_info_entries(); return 0; } -#endif diff --git a/kernel/sound/core/seq/seq_info.h b/kernel/sound/core/seq/seq_info.h index 4892a7f35..f8549f81a 100644 --- a/kernel/sound/core/seq/seq_info.h +++ b/kernel/sound/core/seq/seq_info.h @@ -29,7 +29,7 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry, struct snd_info_buffe void snd_seq_info_queues_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer); -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS int snd_seq_info_init( void ); int snd_seq_info_done( void ); #else diff --git a/kernel/sound/core/seq/seq_memory.c b/kernel/sound/core/seq/seq_memory.c index 801076687..c850345c4 100644 --- a/kernel/sound/core/seq/seq_memory.c +++ b/kernel/sound/core/seq/seq_memory.c @@ -383,15 +383,20 @@ int snd_seq_pool_init(struct snd_seq_pool *pool) if (snd_BUG_ON(!pool)) return -EINVAL; - if (pool->ptr) /* should be atomic? */ - return 0; - pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); - if (!pool->ptr) + cellptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); + if (!cellptr) return -ENOMEM; /* add new cells to the free cell list */ spin_lock_irqsave(&pool->lock, flags); + if (pool->ptr) { + spin_unlock_irqrestore(&pool->lock, flags); + vfree(cellptr); + return 0; + } + + pool->ptr = cellptr; pool->free = NULL; for (cell = 0; cell < pool->size; cell++) { diff --git a/kernel/sound/core/seq/seq_ports.c b/kernel/sound/core/seq/seq_ports.c index 55170a20a..fe686ee41 100644 --- a/kernel/sound/core/seq/seq_ports.c +++ b/kernel/sound/core/seq/seq_ports.c @@ -173,10 +173,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, } /* */ -enum group_type { - SRC_LIST, DEST_LIST -}; - static int subscribe_port(struct snd_seq_client *client, struct snd_seq_client_port *port, struct snd_seq_port_subs_info *grp, @@ -203,6 +199,20 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, return NULL; } +static void delete_and_unsubscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool ack); + +static inline struct snd_seq_subscribers * +get_subscriber(struct list_head *p, bool is_src) +{ + if (is_src) + return list_entry(p, struct snd_seq_subscribers, src_list); + else + return list_entry(p, struct snd_seq_subscribers, dest_list); +} + /* * remove all subscribers on the list * this is called from port_delete, for each src and dest list. @@ -210,7 +220,7 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, static void clear_subscriber_list(struct snd_seq_client *client, struct snd_seq_client_port *port, struct snd_seq_port_subs_info *grp, - int grptype) + int is_src) { struct list_head *p, *n; @@ -219,15 +229,13 @@ static void clear_subscriber_list(struct snd_seq_client *client, struct snd_seq_client *c; struct snd_seq_client_port *aport; - if (grptype == SRC_LIST) { - subs = list_entry(p, struct snd_seq_subscribers, src_list); + subs = get_subscriber(p, is_src); + if (is_src) aport = get_client_port(&subs->info.dest, &c); - } else { - subs = list_entry(p, struct snd_seq_subscribers, dest_list); + else aport = get_client_port(&subs->info.sender, &c); - } - list_del(p); - unsubscribe_port(client, port, grp, &subs->info, 0); + delete_and_unsubscribe_port(client, port, subs, is_src, false); + if (!aport) { /* looks like the connected port is being deleted. * we decrease the counter, and when both ports are deleted @@ -235,21 +243,14 @@ static void clear_subscriber_list(struct snd_seq_client *client, */ if (atomic_dec_and_test(&subs->ref_count)) kfree(subs); - } else { - /* ok we got the connected port */ - struct snd_seq_port_subs_info *agrp; - agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src; - down_write(&agrp->list_mutex); - if (grptype == SRC_LIST) - list_del(&subs->dest_list); - else - list_del(&subs->src_list); - up_write(&agrp->list_mutex); - unsubscribe_port(c, aport, agrp, &subs->info, 1); - kfree(subs); - snd_seq_port_unlock(aport); - snd_seq_client_unlock(c); + continue; } + + /* ok we got the connected port */ + delete_and_unsubscribe_port(c, aport, subs, !is_src, true); + kfree(subs); + snd_seq_port_unlock(aport); + snd_seq_client_unlock(c); } } @@ -262,8 +263,8 @@ static int port_delete(struct snd_seq_client *client, snd_use_lock_sync(&port->use_lock); /* clear subscribers info */ - clear_subscriber_list(client, port, &port->c_src, SRC_LIST); - clear_subscriber_list(client, port, &port->c_dest, DEST_LIST); + clear_subscriber_list(client, port, &port->c_src, true); + clear_subscriber_list(client, port, &port->c_dest, false); if (port->private_free) port->private_free(port->private_data); @@ -479,85 +480,123 @@ static int match_subs_info(struct snd_seq_port_subscribe *r, return 0; } - -/* connect two ports */ -int snd_seq_port_connect(struct snd_seq_client *connector, - struct snd_seq_client *src_client, - struct snd_seq_client_port *src_port, - struct snd_seq_client *dest_client, - struct snd_seq_client_port *dest_port, - struct snd_seq_port_subscribe *info) +static int check_and_subscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool exclusive, bool ack) { - struct snd_seq_port_subs_info *src = &src_port->c_src; - struct snd_seq_port_subs_info *dest = &dest_port->c_dest; - struct snd_seq_subscribers *subs, *s; - int err, src_called = 0; - unsigned long flags; - int exclusive; - - subs = kzalloc(sizeof(*subs), GFP_KERNEL); - if (! subs) - return -ENOMEM; - - subs->info = *info; - atomic_set(&subs->ref_count, 2); + struct snd_seq_port_subs_info *grp; + struct list_head *p; + struct snd_seq_subscribers *s; + int err; - down_write(&src->list_mutex); - down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); - - exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0; + grp = is_src ? &port->c_src : &port->c_dest; err = -EBUSY; + down_write(&grp->list_mutex); if (exclusive) { - if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head)) + if (!list_empty(&grp->list_head)) goto __error; } else { - if (src->exclusive || dest->exclusive) + if (grp->exclusive) goto __error; /* check whether already exists */ - list_for_each_entry(s, &src->list_head, src_list) { - if (match_subs_info(info, &s->info)) - goto __error; - } - list_for_each_entry(s, &dest->list_head, dest_list) { - if (match_subs_info(info, &s->info)) + list_for_each(p, &grp->list_head) { + s = get_subscriber(p, is_src); + if (match_subs_info(&subs->info, &s->info)) goto __error; } } - if ((err = subscribe_port(src_client, src_port, src, info, - connector->number != src_client->number)) < 0) - goto __error; - src_called = 1; - - if ((err = subscribe_port(dest_client, dest_port, dest, info, - connector->number != dest_client->number)) < 0) + err = subscribe_port(client, port, grp, &subs->info, ack); + if (err < 0) { + grp->exclusive = 0; goto __error; + } /* add to list */ - write_lock_irqsave(&src->list_lock, flags); - // write_lock(&dest->list_lock); // no other lock yet - list_add_tail(&subs->src_list, &src->list_head); - list_add_tail(&subs->dest_list, &dest->list_head); - // write_unlock(&dest->list_lock); // no other lock yet - write_unlock_irqrestore(&src->list_lock, flags); + write_lock_irq(&grp->list_lock); + if (is_src) + list_add_tail(&subs->src_list, &grp->list_head); + else + list_add_tail(&subs->dest_list, &grp->list_head); + grp->exclusive = exclusive; + atomic_inc(&subs->ref_count); + write_unlock_irq(&grp->list_lock); + err = 0; - src->exclusive = dest->exclusive = exclusive; + __error: + up_write(&grp->list_mutex); + return err; +} + +static void delete_and_unsubscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool ack) +{ + struct snd_seq_port_subs_info *grp; + struct list_head *list; + bool empty; + + grp = is_src ? &port->c_src : &port->c_dest; + list = is_src ? &subs->src_list : &subs->dest_list; + down_write(&grp->list_mutex); + write_lock_irq(&grp->list_lock); + empty = list_empty(list); + if (!empty) + list_del_init(list); + grp->exclusive = 0; + write_unlock_irq(&grp->list_lock); + up_write(&grp->list_mutex); + + if (!empty) + unsubscribe_port(client, port, grp, &subs->info, ack); +} + +/* connect two ports */ +int snd_seq_port_connect(struct snd_seq_client *connector, + struct snd_seq_client *src_client, + struct snd_seq_client_port *src_port, + struct snd_seq_client *dest_client, + struct snd_seq_client_port *dest_port, + struct snd_seq_port_subscribe *info) +{ + struct snd_seq_subscribers *subs; + bool exclusive; + int err; + + subs = kzalloc(sizeof(*subs), GFP_KERNEL); + if (!subs) + return -ENOMEM; + + subs->info = *info; + atomic_set(&subs->ref_count, 0); + INIT_LIST_HEAD(&subs->src_list); + INIT_LIST_HEAD(&subs->dest_list); + + exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE); + + err = check_and_subscribe_port(src_client, src_port, subs, true, + exclusive, + connector->number != src_client->number); + if (err < 0) + goto error; + err = check_and_subscribe_port(dest_client, dest_port, subs, false, + exclusive, + connector->number != dest_client->number); + if (err < 0) + goto error_dest; - up_write(&dest->list_mutex); - up_write(&src->list_mutex); return 0; - __error: - if (src_called) - unsubscribe_port(src_client, src_port, src, info, - connector->number != src_client->number); + error_dest: + delete_and_unsubscribe_port(src_client, src_port, subs, true, + connector->number != src_client->number); + error: kfree(subs); - up_write(&dest->list_mutex); - up_write(&src->list_mutex); return err; } - /* remove the connection */ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_client *src_client, @@ -567,37 +606,28 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_port_subscribe *info) { struct snd_seq_port_subs_info *src = &src_port->c_src; - struct snd_seq_port_subs_info *dest = &dest_port->c_dest; struct snd_seq_subscribers *subs; int err = -ENOENT; - unsigned long flags; down_write(&src->list_mutex); - down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); - /* look for the connection */ list_for_each_entry(subs, &src->list_head, src_list) { if (match_subs_info(info, &subs->info)) { - write_lock_irqsave(&src->list_lock, flags); - // write_lock(&dest->list_lock); // no lock yet - list_del(&subs->src_list); - list_del(&subs->dest_list); - // write_unlock(&dest->list_lock); - write_unlock_irqrestore(&src->list_lock, flags); - src->exclusive = dest->exclusive = 0; - unsubscribe_port(src_client, src_port, src, info, - connector->number != src_client->number); - unsubscribe_port(dest_client, dest_port, dest, info, - connector->number != dest_client->number); - kfree(subs); + atomic_dec(&subs->ref_count); /* mark as not ready */ err = 0; break; } } - - up_write(&dest->list_mutex); up_write(&src->list_mutex); - return err; + if (err < 0) + return err; + + delete_and_unsubscribe_port(src_client, src_port, subs, true, + connector->number != src_client->number); + delete_and_unsubscribe_port(dest_client, dest_port, subs, false, + connector->number != dest_client->number); + kfree(subs); + return 0; } diff --git a/kernel/sound/core/seq/seq_queue.c b/kernel/sound/core/seq/seq_queue.c index a0cda3820..0bec02e89 100644 --- a/kernel/sound/core/seq/seq_queue.c +++ b/kernel/sound/core/seq/seq_queue.c @@ -142,8 +142,10 @@ static struct snd_seq_queue *queue_new(int owner, int locked) static void queue_delete(struct snd_seq_queue *q) { /* stop and release the timer */ + mutex_lock(&q->timer_mutex); snd_seq_timer_stop(q->timer); snd_seq_timer_close(q); + mutex_unlock(&q->timer_mutex); /* wait until access free */ snd_use_lock_sync(&q->use_lock); /* release resources... */ @@ -753,7 +755,7 @@ int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop) /*----------------------------------------------------------------*/ -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* exported to seq_info.c */ void snd_seq_info_queues_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) @@ -787,5 +789,5 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, queuefree(q); } } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ diff --git a/kernel/sound/core/seq/seq_timer.c b/kernel/sound/core/seq/seq_timer.c index 186f16111..293104926 100644 --- a/kernel/sound/core/seq/seq_timer.c +++ b/kernel/sound/core/seq/seq_timer.c @@ -90,6 +90,9 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr) void snd_seq_timer_defaults(struct snd_seq_timer * tmr) { + unsigned long flags; + + spin_lock_irqsave(&tmr->lock, flags); /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ @@ -105,21 +108,25 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) tmr->preferred_resolution = seq_default_timer_resolution; tmr->skew = tmr->skew_base = SKEW_BASE; + spin_unlock_irqrestore(&tmr->lock, flags); } -void snd_seq_timer_reset(struct snd_seq_timer * tmr) +static void seq_timer_reset(struct snd_seq_timer *tmr) { - unsigned long flags; - - spin_lock_irqsave(&tmr->lock, flags); - /* reset time & songposition */ tmr->cur_time.tv_sec = 0; tmr->cur_time.tv_nsec = 0; tmr->tick.cur_tick = 0; tmr->tick.fraction = 0; +} + +void snd_seq_timer_reset(struct snd_seq_timer *tmr) +{ + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); + seq_timer_reset(tmr); spin_unlock_irqrestore(&tmr->lock, flags); } @@ -138,8 +145,11 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, tmr = q->timer; if (tmr == NULL) return; - if (!tmr->running) + spin_lock_irqsave(&tmr->lock, flags); + if (!tmr->running) { + spin_unlock_irqrestore(&tmr->lock, flags); return; + } resolution *= ticks; if (tmr->skew != tmr->skew_base) { @@ -148,8 +158,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, (((resolution & 0xffff) * tmr->skew) >> 16); } - spin_lock_irqsave(&tmr->lock, flags); - /* update timer */ snd_seq_inc_time_nsec(&tmr->cur_time, resolution); @@ -296,26 +304,30 @@ int snd_seq_timer_open(struct snd_seq_queue *q) t->callback = snd_seq_timer_interrupt; t->callback_data = q; t->flags |= SNDRV_TIMER_IFLG_AUTO; + spin_lock_irq(&tmr->lock); tmr->timeri = t; + spin_unlock_irq(&tmr->lock); return 0; } int snd_seq_timer_close(struct snd_seq_queue *q) { struct snd_seq_timer *tmr; + struct snd_timer_instance *t; tmr = q->timer; if (snd_BUG_ON(!tmr)) return -EINVAL; - if (tmr->timeri) { - snd_timer_stop(tmr->timeri); - snd_timer_close(tmr->timeri); - tmr->timeri = NULL; - } + spin_lock_irq(&tmr->lock); + t = tmr->timeri; + tmr->timeri = NULL; + spin_unlock_irq(&tmr->lock); + if (t) + snd_timer_close(t); return 0; } -int snd_seq_timer_stop(struct snd_seq_timer * tmr) +static int seq_timer_stop(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; @@ -326,6 +338,17 @@ int snd_seq_timer_stop(struct snd_seq_timer * tmr) return 0; } +int snd_seq_timer_stop(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_stop(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + static int initialize_timer(struct snd_seq_timer *tmr) { struct snd_timer *t; @@ -358,13 +381,13 @@ static int initialize_timer(struct snd_seq_timer *tmr) return 0; } -int snd_seq_timer_start(struct snd_seq_timer * tmr) +static int seq_timer_start(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; if (tmr->running) - snd_seq_timer_stop(tmr); - snd_seq_timer_reset(tmr); + seq_timer_stop(tmr); + seq_timer_reset(tmr); if (initialize_timer(tmr) < 0) return -EINVAL; snd_timer_start(tmr->timeri, tmr->ticks); @@ -373,14 +396,25 @@ int snd_seq_timer_start(struct snd_seq_timer * tmr) return 0; } -int snd_seq_timer_continue(struct snd_seq_timer * tmr) +int snd_seq_timer_start(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_start(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + +static int seq_timer_continue(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; if (tmr->running) return -EBUSY; if (! tmr->initialized) { - snd_seq_timer_reset(tmr); + seq_timer_reset(tmr); if (initialize_timer(tmr) < 0) return -EINVAL; } @@ -390,11 +424,24 @@ int snd_seq_timer_continue(struct snd_seq_timer * tmr) return 0; } +int snd_seq_timer_continue(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_continue(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + /* return current 'real' time. use timeofday() to get better granularity. */ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) { snd_seq_real_time_t cur_time; + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); cur_time = tmr->cur_time; if (tmr->running) { struct timeval tm; @@ -410,7 +457,7 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) } snd_seq_sanity_real_time(&cur_time); } - + spin_unlock_irqrestore(&tmr->lock, flags); return cur_time; } @@ -422,7 +469,7 @@ snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr) } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* exported to seq_info.c */ void snd_seq_info_timer_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) @@ -449,5 +496,5 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry, queuefree(q); } } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ diff --git a/kernel/sound/core/seq/seq_virmidi.c b/kernel/sound/core/seq/seq_virmidi.c index 56e0f4cd3..81134e067 100644 --- a/kernel/sound/core/seq/seq_virmidi.c +++ b/kernel/sound/core/seq/seq_virmidi.c @@ -155,21 +155,26 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, struct snd_virmidi *vmidi = substream->runtime->private_data; int count, res; unsigned char buf[32], *pbuf; + unsigned long flags; if (up) { vmidi->trigger = 1; if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - snd_rawmidi_transmit_ack(substream, substream->runtime->buffer_size - substream->runtime->avail); - return; /* ignored */ + while (snd_rawmidi_transmit(substream, buf, + sizeof(buf)) > 0) { + /* ignored */ + } + return; } if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) return; vmidi->event.type = SNDRV_SEQ_EVENT_NONE; } + spin_lock_irqsave(&substream->runtime->lock, flags); while (1) { - count = snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); + count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); if (count <= 0) break; pbuf = buf; @@ -179,16 +184,18 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, snd_midi_event_reset_encode(vmidi->parser); continue; } - snd_rawmidi_transmit_ack(substream, res); + __snd_rawmidi_transmit_ack(substream, res); pbuf += res; count -= res; if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - return; + goto out; vmidi->event.type = SNDRV_SEQ_EVENT_NONE; } } } + out: + spin_unlock_irqrestore(&substream->runtime->lock, flags); } else { vmidi->trigger = 0; } @@ -254,9 +261,13 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) */ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) { + struct snd_virmidi_dev *rdev = substream->rmidi->private_data; struct snd_virmidi *vmidi = substream->runtime->private_data; - snd_midi_event_free(vmidi->parser); + + write_lock_irq(&rdev->filelist_lock); list_del(&vmidi->list); + write_unlock_irq(&rdev->filelist_lock); + snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; kfree(vmidi); return 0; |