#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <sound/control.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ALSA timer interface");
MODULE_LICENSE("GPL");
-MODULE_CLASSES("{sound}");
-MODULE_PARM(timer_limit, "i");
+module_param(timer_limit, int, 0444);
MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
typedef struct {
static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *timer)
{
snd_timer_instance_t *timeri;
- timeri = snd_kcalloc(sizeof(snd_timer_instance_t), GFP_KERNEL);
+ timeri = kcalloc(1, sizeof(*timeri), GFP_KERNEL);
if (timeri == NULL)
return NULL;
timeri->owner = snd_kmalloc_strdup(owner, GFP_KERNEL);
snd_assert(tid != NULL, return -EINVAL);
snd_assert(rtimer != NULL, return -EINVAL);
*rtimer = NULL;
- timer = snd_magic_kcalloc(snd_timer_t, 0, GFP_KERNEL);
+ timer = kcalloc(1, sizeof(*timer), GFP_KERNEL);
if (timer == NULL)
return -ENOMEM;
timer->tmr_class = tid->dev_class;
snd_assert(timer != NULL, return -ENXIO);
if (timer->private_free)
timer->private_free(timer);
- snd_magic_kfree(timer);
+ kfree(timer);
return 0;
}
int snd_timer_dev_free(snd_device_t *device)
{
- snd_timer_t *timer = snd_magic_cast(snd_timer_t, device->device_data, return -ENXIO);
+ snd_timer_t *timer = device->device_data;
return snd_timer_free(timer);
}
int snd_timer_dev_register(snd_device_t *dev)
{
- snd_timer_t *timer = snd_magic_cast(snd_timer_t, dev->device_data, return -ENXIO);
+ snd_timer_t *timer = dev->device_data;
snd_timer_t *timer1;
struct list_head *p;
static int snd_timer_dev_unregister(snd_device_t *device)
{
- snd_timer_t *timer = snd_magic_cast(snd_timer_t, device->device_data, return -ENXIO);
+ snd_timer_t *timer = device->device_data;
return snd_timer_unregister(timer);
}
return err;
strcpy(timer->name, "system timer");
timer->hw = snd_timer_system;
- priv = (struct snd_timer_system_private *) snd_kcalloc(sizeof(struct snd_timer_system_private), GFP_KERNEL);
+ priv = kcalloc(1, sizeof(*priv), GFP_KERNEL);
if (priv == NULL) {
snd_timer_free(timer);
return -ENOMEM;
unsigned long resolution,
unsigned long ticks)
{
- snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
+ snd_timer_user_t *tu = timeri->callback_data;
snd_timer_read_t *r;
int prev;
struct timespec *tstamp,
unsigned long resolution)
{
- snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
+ snd_timer_user_t *tu = timeri->callback_data;
snd_timer_tread_t r1;
if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE)
unsigned long resolution,
unsigned long ticks)
{
- snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
+ snd_timer_user_t *tu = timeri->callback_data;
snd_timer_tread_t *r, r1;
struct timespec tstamp;
int prev, append = 0;
{
snd_timer_user_t *tu;
- tu = snd_magic_kcalloc(snd_timer_user_t, 0, GFP_KERNEL);
+ tu = kcalloc(1, sizeof(*tu), GFP_KERNEL);
if (tu == NULL)
return -ENOMEM;
spin_lock_init(&tu->qlock);
tu->queue_size = 128;
tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
if (tu->queue == NULL) {
- snd_magic_kfree(tu);
+ kfree(tu);
return -ENOMEM;
}
file->private_data = tu;
snd_timer_user_t *tu;
if (file->private_data) {
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
file->private_data = NULL;
fasync_helper(-1, file, 0, &tu->fasync);
if (tu->timeri)
kfree(tu->queue);
if (tu->tqueue)
kfree(tu->tqueue);
- snd_magic_kfree(tu);
+ kfree(tu);
}
return 0;
}
id->subdevice = timer->tmr_subdevice;
}
-static int snd_timer_user_next_device(snd_timer_id_t *_tid)
+static int snd_timer_user_next_device(snd_timer_id_t __user *_tid)
{
snd_timer_id_t id;
snd_timer_t *timer;
return 0;
}
-static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t *_ginfo)
+static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_ginfo)
{
snd_timer_ginfo_t ginfo;
snd_timer_id_t tid;
return err;
}
-static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t *_gparams)
+static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user *_gparams)
{
snd_timer_gparams_t gparams;
snd_timer_t *t;
return err;
}
-static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t *_gstatus)
+static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user *_gstatus)
{
snd_timer_gstatus_t gstatus;
snd_timer_id_t tid;
err = -ENODEV;
}
up(®ister_mutex);
- if (err >= 0 && copy_from_user(_gstatus, &gstatus, sizeof(gstatus)))
+ if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
err = -EFAULT;
return err;
}
-static int snd_timer_user_tselect(struct file *file, snd_timer_select_t *_tselect)
+static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *_tselect)
{
snd_timer_user_t *tu;
snd_timer_select_t tselect;
char str[32];
int err;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
if (tu->timeri)
snd_timer_close(tu->timeri);
if (copy_from_user(&tselect, _tselect, sizeof(tselect)))
return 0;
}
-static int snd_timer_user_info(struct file *file, snd_timer_info_t *_info)
+static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info)
{
snd_timer_user_t *tu;
snd_timer_info_t info;
snd_timer_t *t;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
t = tu->timeri->timer;
snd_assert(t != NULL, return -ENXIO);
return 0;
}
-static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params)
+static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_params)
{
- unsigned long flags;
snd_timer_user_t *tu;
snd_timer_params_t params;
snd_timer_t *t;
snd_timer_tread_t *ttr;
int err;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
t = tu->timeri->timer;
snd_assert(t != NULL, return -ENXIO);
goto _end;
}
snd_timer_stop(tu->timeri);
- spin_lock_irqsave(&t->lock, flags);
- if (params.flags & SNDRV_TIMER_PSFLG_AUTO) {
+ spin_lock_irq(&t->lock);
+ tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
+ SNDRV_TIMER_IFLG_EXCLUSIVE|
+ SNDRV_TIMER_IFLG_EARLY_EVENT);
+ if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
- } else {
- tu->timeri->flags &= ~SNDRV_TIMER_IFLG_AUTO;
- }
- if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE) {
+ if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
- } else {
- tu->timeri->flags &= ~SNDRV_TIMER_IFLG_EXCLUSIVE;
- }
- spin_unlock_irqrestore(&t->lock, flags);
+ if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
+ tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
+ spin_unlock_irq(&t->lock);
if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) {
if (tu->tread) {
ttr = (snd_timer_tread_t *)kmalloc(params.queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
}
}
}
+ tu->qhead = tu->qtail = tu->qused = 0;
+ if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
+ if (tu->tread) {
+ snd_timer_tread_t tread;
+ tread.event = SNDRV_TIMER_EVENT_EARLY;
+ tread.tstamp.tv_sec = 0;
+ tread.tstamp.tv_nsec = 0;
+ tread.val = 0;
+ snd_timer_user_append_to_tqueue(tu, &tread);
+ } else {
+ snd_timer_read_t *r = &tu->queue[0];
+ r->resolution = 0;
+ r->ticks = 0;
+ tu->qused++;
+ tu->qtail++;
+ }
+
+ }
tu->filter = params.filter;
tu->ticks = params.ticks;
err = 0;
return err;
}
-static int snd_timer_user_status(struct file *file, snd_timer_status_t *_status)
+static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_status)
{
- unsigned long flags;
snd_timer_user_t *tu;
snd_timer_status_t status;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp;
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
- spin_lock_irqsave(&tu->qlock, flags);
+ spin_lock_irq(&tu->qlock);
status.queue = tu->qused;
- spin_unlock_irqrestore(&tu->qlock, flags);
+ spin_unlock_irq(&tu->qlock);
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
int err;
snd_timer_user_t *tu;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
snd_timer_stop(tu->timeri);
tu->timeri->lost = 0;
int err;
snd_timer_user_t *tu;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
}
int err;
snd_timer_user_t *tu;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
tu->timeri->lost = 0;
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
}
-static int snd_timer_user_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
snd_timer_user_t *tu;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
switch (cmd) {
case SNDRV_TIMER_IOCTL_PVERSION:
- return put_user(SNDRV_TIMER_VERSION, (int *)arg) ? -EFAULT : 0;
+ return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0;
case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
- return snd_timer_user_next_device((snd_timer_id_t *)arg);
+ return snd_timer_user_next_device(argp);
case SNDRV_TIMER_IOCTL_TREAD:
{
int xarg;
if (tu->timeri) /* too late */
return -EBUSY;
- if (get_user(xarg, (int *) arg))
+ if (get_user(xarg, p))
return -EFAULT;
tu->tread = xarg ? 1 : 0;
return 0;
}
case SNDRV_TIMER_IOCTL_GINFO:
- return snd_timer_user_ginfo(file, (snd_timer_ginfo_t *)arg);
+ return snd_timer_user_ginfo(file, argp);
case SNDRV_TIMER_IOCTL_GPARAMS:
- return snd_timer_user_gparams(file, (snd_timer_gparams_t *)arg);
+ return snd_timer_user_gparams(file, argp);
case SNDRV_TIMER_IOCTL_GSTATUS:
- return snd_timer_user_gstatus(file, (snd_timer_gstatus_t *)arg);
+ return snd_timer_user_gstatus(file, argp);
case SNDRV_TIMER_IOCTL_SELECT:
- return snd_timer_user_tselect(file, (snd_timer_select_t *)arg);
+ return snd_timer_user_tselect(file, argp);
case SNDRV_TIMER_IOCTL_INFO:
- return snd_timer_user_info(file, (snd_timer_info_t *)arg);
+ return snd_timer_user_info(file, argp);
case SNDRV_TIMER_IOCTL_PARAMS:
- return snd_timer_user_params(file, (snd_timer_params_t *)arg);
+ return snd_timer_user_params(file, argp);
case SNDRV_TIMER_IOCTL_STATUS:
- return snd_timer_user_status(file, (snd_timer_status_t *)arg);
+ return snd_timer_user_status(file, argp);
case SNDRV_TIMER_IOCTL_START:
return snd_timer_user_start(file);
case SNDRV_TIMER_IOCTL_STOP:
return -ENOTTY;
}
+/* FIXME: need to unlock BKL to allow preemption */
+static int snd_timer_user_ioctl(struct inode *inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int err;
+ unlock_kernel();
+ err = _snd_timer_user_ioctl(inode, file, cmd, arg);
+ lock_kernel();
+ return err;
+}
+
static int snd_timer_user_fasync(int fd, struct file * file, int on)
{
snd_timer_user_t *tu;
int err;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
err = fasync_helper(fd, file, on, &tu->fasync);
if (err < 0)
return err;
return 0;
}
-static ssize_t snd_timer_user_read(struct file *file, char *buffer, size_t count, loff_t *offset)
+static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_t count, loff_t *offset)
{
snd_timer_user_t *tu;
long result = 0, unit;
int err = 0;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+ tu = file->private_data;
unit = tu->tread ? sizeof(snd_timer_tread_t) : sizeof(snd_timer_read_t);
spin_lock_irq(&tu->qlock);
while ((long)count - result >= unit) {
unsigned int mask;
snd_timer_user_t *tu;
- tu = snd_magic_cast(snd_timer_user_t, file->private_data, return 0);
+ tu = file->private_data;
poll_wait(file, &tu->qchange_sleep, wait);
module_init(alsa_timer_init)
module_exit(alsa_timer_exit)
-#ifndef MODULE
-/* format is: snd-timer=timer_limit */
-
-static int __init alsa_timer_setup(char *str)
-{
- (void)(get_option(&str,&timer_limit) == 2);
- return 1;
-}
-
-__setup("snd-timer=", alsa_timer_setup);
-#endif /* ifndef MODULE */
-
EXPORT_SYMBOL(snd_timer_open);
EXPORT_SYMBOL(snd_timer_close);
EXPORT_SYMBOL(snd_timer_resolution);