#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/mutex.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
#include <sound/core.h>
struct timespec tstamp; /* trigger tstamp */
wait_queue_head_t qchange_sleep;
struct fasync_struct *fasync;
- struct semaphore tread_sem;
+ struct mutex tread_sem;
};
/* list of timers */
/* lock for slave active lists */
static DEFINE_SPINLOCK(slave_active_lock);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
static int snd_timer_free(struct snd_timer *timer);
static int snd_timer_dev_free(struct snd_device *device);
static int snd_timer_dev_register(struct snd_device *device);
-static int snd_timer_dev_unregister(struct snd_device *device);
+static int snd_timer_dev_disconnect(struct snd_device *device);
static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
snd_printd("invalid slave class %i\n", tid->dev_sclass);
return -EINVAL;
}
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
timeri = snd_timer_instance_new(owner, NULL);
if (!timeri) {
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
return -ENOMEM;
}
timeri->slave_class = tid->dev_sclass;
timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
list_add_tail(&timeri->open_list, &snd_timer_slave_list);
snd_timer_check_slave(timeri);
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
*ti = timeri;
return 0;
}
/* open a master instance */
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
timer = snd_timer_find(tid);
#ifdef CONFIG_KMOD
if (timer == NULL) {
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
snd_timer_request(tid);
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
timer = snd_timer_find(tid);
}
#endif
if (!timer) {
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
return -ENODEV;
}
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) {
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
return -EBUSY;
}
}
timeri = snd_timer_instance_new(owner, timer);
if (!timeri) {
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
return -ENOMEM;
}
timeri->slave_class = tid->dev_sclass;
timer->hw.open(timer);
list_add_tail(&timeri->open_list, &timer->open_list_head);
snd_timer_check_master(timeri);
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
*ti = timeri;
return 0;
}
spin_lock_irq(&slave_active_lock);
}
spin_unlock_irq(&slave_active_lock);
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
list_del(&timeri->open_list);
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
} else {
timer = timeri->timer;
/* wait, until the active callback is finished */
spin_lock_irq(&timer->lock);
}
spin_unlock_irq(&timer->lock);
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
list_del(&timeri->open_list);
if (timer && list_empty(&timer->open_list_head) &&
timer->hw.close)
slave->timer = NULL;
spin_unlock_irq(&slave_active_lock);
}
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
}
if (timeri->private_free)
timeri->private_free(timeri);
}
}
if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
- snd_timer_reschedule(timer, ticks_left);
+ snd_timer_reschedule(timer, timer->sticks);
if (timer->running) {
if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
timer->hw.stop(timer);
static struct snd_device_ops ops = {
.dev_free = snd_timer_dev_free,
.dev_register = snd_timer_dev_register,
- .dev_unregister = snd_timer_dev_unregister
+ .dev_disconnect = snd_timer_dev_disconnect,
};
snd_assert(tid != NULL, return -EINVAL);
static int snd_timer_free(struct snd_timer *timer)
{
snd_assert(timer != NULL, return -ENXIO);
+
+ mutex_lock(®ister_mutex);
+ if (! list_empty(&timer->open_list_head)) {
+ struct list_head *p, *n;
+ struct snd_timer_instance *ti;
+ snd_printk(KERN_WARNING "timer %p is busy?\n", timer);
+ list_for_each_safe(p, n, &timer->open_list_head) {
+ list_del_init(p);
+ ti = list_entry(p, struct snd_timer_instance, open_list);
+ ti->timer = NULL;
+ }
+ }
+ list_del(&timer->device_list);
+ mutex_unlock(®ister_mutex);
+
if (timer->private_free)
timer->private_free(timer);
kfree(timer);
!timer->hw.resolution && timer->hw.c_resolution == NULL)
return -EINVAL;
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
list_for_each(p, &snd_timer_list) {
timer1 = list_entry(p, struct snd_timer, device_list);
if (timer1->tmr_class > timer->tmr_class)
if (timer1->tmr_subdevice < timer->tmr_subdevice)
continue;
/* conflicts.. */
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
return -EBUSY;
}
list_add_tail(&timer->device_list, p);
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
return 0;
}
-static int snd_timer_unregister(struct snd_timer *timer)
-{
- struct list_head *p, *n;
- struct snd_timer_instance *ti;
-
- snd_assert(timer != NULL, return -ENXIO);
- down(®ister_mutex);
- if (! list_empty(&timer->open_list_head)) {
- snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
- list_for_each_safe(p, n, &timer->open_list_head) {
- list_del_init(p);
- ti = list_entry(p, struct snd_timer_instance, open_list);
- ti->timer = NULL;
- }
- }
- list_del(&timer->device_list);
- up(®ister_mutex);
- return snd_timer_free(timer);
-}
-
-static int snd_timer_dev_unregister(struct snd_device *device)
+static int snd_timer_dev_disconnect(struct snd_device *device)
{
struct snd_timer *timer = device->device_data;
- return snd_timer_unregister(timer);
+ mutex_lock(®ister_mutex);
+ list_del_init(&timer->device_list);
+ mutex_unlock(®ister_mutex);
+ return 0;
}
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp)
return snd_timer_dev_register(&dev);
}
-int snd_timer_global_unregister(struct snd_timer *timer)
-{
- return snd_timer_unregister(timer);
-}
-
/*
* System timer
*/
struct snd_timer_system_private {
struct timer_list tlist;
- struct timer * timer;
unsigned long last_expires;
unsigned long last_jiffies;
unsigned long correction;
struct snd_timer_system_private *priv = timer->private_data;
unsigned long jiff = jiffies;
if (time_after(jiff, priv->last_expires))
- priv->correction = (long)jiff - (long)priv->last_expires;
+ priv->correction += (long)jiff - (long)priv->last_expires;
snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
}
njiff++;
} else {
njiff += timer->sticks - priv->correction;
- priv->correction -= timer->sticks;
+ priv->correction = 0;
}
priv->last_expires = priv->tlist.expires = njiff;
add_timer(&priv->tlist);
timer->sticks = priv->last_expires - jiff;
else
timer->sticks = 1;
+ priv->correction = 0;
return 0;
}
static void snd_timer_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- unsigned long flags;
struct snd_timer *timer;
struct snd_timer_instance *ti;
struct list_head *p, *q;
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
list_for_each(p, &snd_timer_list) {
timer = list_entry(p, struct snd_timer, device_list);
switch (timer->tmr_class) {
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
snd_iprintf(buffer, " SLAVE");
snd_iprintf(buffer, "\n");
- spin_lock_irqsave(&timer->lock, flags);
list_for_each(q, &timer->open_list_head) {
ti = list_entry(q, struct snd_timer_instance, open_list);
snd_iprintf(buffer, " Client %s : %s\n",
SNDRV_TIMER_IFLG_RUNNING)
? "running" : "stopped");
}
- spin_unlock_irqrestore(&timer->lock, flags);
}
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
}
-static struct snd_info_entry *snd_timer_proc_entry = NULL;
+static struct snd_info_entry *snd_timer_proc_entry;
static void __init snd_timer_proc_init(void)
{
entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL);
if (entry != NULL) {
- entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128;
entry->c.text.read = snd_timer_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
static void __exit snd_timer_proc_done(void)
{
- snd_info_unregister(snd_timer_proc_entry);
+ snd_info_free_entry(snd_timer_proc_entry);
}
#else /* !CONFIG_PROC_FS */
#define snd_timer_proc_init()
return -ENOMEM;
spin_lock_init(&tu->qlock);
init_waitqueue_head(&tu->qchange_sleep);
- init_MUTEX(&tu->tread_sem);
+ mutex_init(&tu->tread_sem);
tu->ticks = 1;
tu->queue_size = 128;
tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
if (copy_from_user(&id, _tid, sizeof(id)))
return -EFAULT;
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
if (id.dev_class < 0) { /* first item */
if (list_empty(&snd_timer_list))
snd_timer_user_zero_id(&id);
snd_timer_user_zero_id(&id);
}
}
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
if (copy_to_user(_tid, &id, sizeof(*_tid)))
return -EFAULT;
return 0;
tid = ginfo->tid;
memset(ginfo, 0, sizeof(*ginfo));
ginfo->tid = tid;
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
t = snd_timer_find(&tid);
if (t != NULL) {
ginfo->card = t->card ? t->card->number : -1;
} else {
err = -ENODEV;
}
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
err = -EFAULT;
kfree(ginfo);
if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
return -EFAULT;
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
t = snd_timer_find(&gparams.tid);
if (!t) {
err = -ENODEV;
}
err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
_error:
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
return err;
}
tid = gstatus.tid;
memset(&gstatus, 0, sizeof(gstatus));
gstatus.tid = tid;
- down(®ister_mutex);
+ mutex_lock(®ister_mutex);
t = snd_timer_find(&tid);
if (t != NULL) {
if (t->hw.c_resolution)
} else {
err = -ENODEV;
}
- up(®ister_mutex);
+ mutex_unlock(®ister_mutex);
if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
err = -EFAULT;
return err;
int err = 0;
tu = file->private_data;
- down(&tu->tread_sem);
+ mutex_lock(&tu->tread_sem);
if (tu->timeri) {
snd_timer_close(tu->timeri);
tu->timeri = NULL;
}
__err:
- up(&tu->tread_sem);
+ mutex_unlock(&tu->tread_sem);
return err;
}
{
int xarg;
- down(&tu->tread_sem);
+ mutex_lock(&tu->tread_sem);
if (tu->timeri) { /* too late */
- up(&tu->tread_sem);
+ mutex_unlock(&tu->tread_sem);
return -EBUSY;
}
if (get_user(xarg, p)) {
- up(&tu->tread_sem);
+ mutex_unlock(&tu->tread_sem);
return -EFAULT;
}
tu->tread = xarg ? 1 : 0;
- up(&tu->tread_sem);
+ mutex_unlock(&tu->tread_sem);
return 0;
}
case SNDRV_TIMER_IOCTL_GINFO:
/* unregister the system timer */
list_for_each_safe(p, n, &snd_timer_list) {
struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
- snd_timer_unregister(timer);
+ snd_timer_free(timer);
}
snd_timer_proc_done();
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
EXPORT_SYMBOL(snd_timer_global_new);
EXPORT_SYMBOL(snd_timer_global_free);
EXPORT_SYMBOL(snd_timer_global_register);
-EXPORT_SYMBOL(snd_timer_global_unregister);
EXPORT_SYMBOL(snd_timer_interrupt);