X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Fcore%2Ftimer.c;h=cee5f47c780d3e08af7e9ee2b63481ca02a60163;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=35c5d05f228ac32eab2bcc35702ab82e87a135ab;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/sound/core/timer.c b/sound/core/timer.c index 35c5d05f2..cee5f47c7 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -22,8 +22,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -45,8 +47,7 @@ static int timer_limit = DEFAULT_TIMER_LIMIT; MODULE_AUTHOR("Jaroslav Kysela , Takashi Iwai "); 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 { @@ -93,7 +94,7 @@ static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left); 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); @@ -760,7 +761,7 @@ int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t * 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; @@ -791,19 +792,19 @@ static int snd_timer_free(snd_timer_t *timer) 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; @@ -864,7 +865,7 @@ int snd_timer_unregister(snd_timer_t *timer) 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); } @@ -1017,7 +1018,7 @@ static int snd_timer_register_system(void) 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; @@ -1085,7 +1086,7 @@ static void snd_timer_user_interrupt(snd_timer_instance_t *timeri, 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; @@ -1128,7 +1129,7 @@ static void snd_timer_user_ccallback(snd_timer_instance_t *timeri, 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) @@ -1147,7 +1148,7 @@ static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri, 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; @@ -1199,7 +1200,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) { 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); @@ -1208,7 +1209,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) 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; @@ -1220,7 +1221,7 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) 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) @@ -1229,7 +1230,7 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) kfree(tu->queue); if (tu->tqueue) kfree(tu->tqueue); - snd_magic_kfree(tu); + kfree(tu); } return 0; } @@ -1252,7 +1253,7 @@ static void snd_timer_user_copy_id(snd_timer_id_t *id, snd_timer_t *timer) 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; @@ -1343,7 +1344,7 @@ static int snd_timer_user_next_device(snd_timer_id_t *_tid) 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; @@ -1381,7 +1382,7 @@ static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t *_ginfo) 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; @@ -1407,7 +1408,7 @@ static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t *_gpara 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; @@ -1436,19 +1437,19 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t *_gstat 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))) @@ -1488,13 +1489,13 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t *_tselec 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); @@ -1510,9 +1511,8 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t *_info) 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; @@ -1520,7 +1520,7 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params) 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); @@ -1548,18 +1548,17 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params) 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); @@ -1577,6 +1576,24 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params) } } } + 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; @@ -1586,22 +1603,21 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params) 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; @@ -1612,7 +1628,7 @@ static int snd_timer_user_start(struct file *file) 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; @@ -1625,7 +1641,7 @@ static int snd_timer_user_stop(struct file *file) 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; } @@ -1635,48 +1651,50 @@ static int snd_timer_user_continue(struct file *file) 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: @@ -1687,25 +1705,36 @@ static int snd_timer_user_ioctl(struct inode *inode, struct file *file, 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) { @@ -1767,7 +1796,7 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) 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); @@ -1848,18 +1877,6 @@ static void __exit alsa_timer_exit(void) 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);