timer.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,895 行 · 第 1/4 页
C
1,895 行
if (!keep_flag) { spin_lock_irqsave(&slave_active_lock, flags); timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; spin_unlock_irqrestore(&slave_active_lock, flags); } goto __end; } timer = timeri->timer; if (!timer) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); list_del_init(&timeri->ack_list); list_del_init(&timeri->active_list); if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && !(--timer->running)) { timer->hw.stop(timer); if (timer->flags & SNDRV_TIMER_FLG_RESCHED) { timer->flags &= ~SNDRV_TIMER_FLG_RESCHED; snd_timer_reschedule(timer, 0); if (timer->flags & SNDRV_TIMER_FLG_CHANGE) { timer->flags &= ~SNDRV_TIMER_FLG_CHANGE; timer->hw.start(timer); } } } if (!keep_flag) timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING|SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) snd_timer_notify1(timeri, event); return 0;}/* * stop the timer instance. * * do not call this from the timer callback! */int snd_timer_stop(snd_timer_instance_t * timeri){ snd_timer_t *timer; unsigned long flags; int err; err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); if (err < 0) return err; timer = timeri->timer; spin_lock_irqsave(&timer->lock, flags); timeri->cticks = timeri->ticks; timeri->pticks = 0; spin_unlock_irqrestore(&timer->lock, flags); return 0;}/* * start again.. the tick is kept. */int snd_timer_continue(snd_timer_instance_t * timeri){ snd_timer_t *timer; int result = -EINVAL; unsigned long flags; if (timeri == NULL) return result; if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) return snd_timer_start_slave(timeri); timer = timeri->timer; if (! timer) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); if (!timeri->cticks) timeri->cticks = 1; timeri->pticks = 0; result = snd_timer_start1(timer, timeri, timer->sticks); spin_unlock_irqrestore(&timer->lock, flags); snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); return result;}/* * pause.. remember the ticks left */int snd_timer_pause(snd_timer_instance_t * timeri){ return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE);}/* * reschedule the timer * * start pending instances and check the scheduling ticks. * when the scheduling ticks is changed set CHANGE flag to reprogram the timer. */static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left){ snd_timer_instance_t *ti; unsigned long ticks = ~0UL; struct list_head *p; list_for_each(p, &timer->active_list_head) { ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list); if (ti->flags & SNDRV_TIMER_IFLG_START) { ti->flags &= ~SNDRV_TIMER_IFLG_START; ti->flags |= SNDRV_TIMER_IFLG_RUNNING; timer->running++; } if (ti->flags & SNDRV_TIMER_IFLG_RUNNING) { if (ticks > ti->cticks) ticks = ti->cticks; } } if (ticks == ~0UL) { timer->flags &= ~SNDRV_TIMER_FLG_RESCHED; return; } if (ticks > timer->hw.ticks) ticks = timer->hw.ticks; if (ticks_left != ticks) timer->flags |= SNDRV_TIMER_FLG_CHANGE; timer->sticks = ticks;}/* * timer tasklet * */static void snd_timer_tasklet(unsigned long arg){ snd_timer_t *timer = (snd_timer_t *) arg; snd_timer_instance_t *ti; struct list_head *p; unsigned long resolution, ticks; spin_lock(&timer->lock); /* now process all callbacks */ while (!list_empty(&timer->sack_list_head)) { p = timer->sack_list_head.next; /* get first item */ ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, 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; } spin_unlock(&timer->lock);}/* * timer interrupt * * ticks_left is usually equal to timer->sticks. * */void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left){ snd_timer_instance_t *ti, *ts; unsigned long resolution, ticks; struct list_head *p, *q, *n; int use_tasklet = 0; if (timer == NULL) return; spin_lock(&timer->lock); /* remember the current resolution */ if (timer->hw.c_resolution) resolution = timer->hw.c_resolution(timer); else resolution = timer->hw.resolution; /* loop for all active instances * here we cannot use list_for_each because the active_list of a processed * instance is relinked to done_list_head before callback is called. */ list_for_each_safe(p, n, &timer->active_list_head) { ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list); if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) continue; ti->pticks += ticks_left; ti->resolution = resolution; if (ti->cticks < ticks_left) ti->cticks = 0; else ti->cticks -= ticks_left; if (ti->cticks) /* not expired */ continue; if (ti->flags & SNDRV_TIMER_IFLG_AUTO) { ti->cticks = ti->ticks; } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (--timer->running) list_del(p); } if (list_empty(&ti->ack_list)) { if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) { list_add_tail(&ti->ack_list, &timer->ack_list_head); } else { list_add_tail(&ti->ack_list, &timer->sack_list_head); } } list_for_each(q, &ti->slave_active_head) { ts = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, active_list); ts->pticks = ti->pticks; ts->resolution = resolution; if (list_empty(&ts->ack_list)) { if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) { list_add_tail(&ts->ack_list, &timer->ack_list_head); } else { list_add_tail(&ts->ack_list, &timer->sack_list_head); } } } } if (timer->flags & SNDRV_TIMER_FLG_RESCHED) snd_timer_reschedule(timer, ticks_left); if (timer->running) { if (timer->hw.flags & SNDRV_TIMER_HW_STOP) { timer->hw.stop(timer); timer->flags |= SNDRV_TIMER_FLG_CHANGE; } if (!(timer->hw.flags & SNDRV_TIMER_HW_AUTO) || (timer->flags & SNDRV_TIMER_FLG_CHANGE)) { /* restart timer */ timer->flags &= ~SNDRV_TIMER_FLG_CHANGE; timer->hw.start(timer); } } else { timer->hw.stop(timer); } /* now process all fast callbacks */ while (!list_empty(&timer->ack_list_head)) { p = timer->ack_list_head.next; /* get first item */ ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, 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; } /* do we have any slow callbacks? */ use_tasklet = !list_empty(&timer->sack_list_head); spin_unlock(&timer->lock); if (use_tasklet) tasklet_hi_schedule(&timer->task_queue);}/* */int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t ** rtimer){ snd_timer_t *timer; int err; static snd_device_ops_t ops = { .dev_free = snd_timer_dev_free, .dev_register = snd_timer_dev_register, .dev_unregister = snd_timer_dev_unregister }; snd_assert(tid != NULL, return -EINVAL); snd_assert(rtimer != NULL, return -EINVAL); *rtimer = NULL; timer = kcalloc(1, sizeof(*timer), GFP_KERNEL); if (timer == NULL) return -ENOMEM; timer->tmr_class = tid->dev_class; timer->card = card; timer->tmr_device = tid->device; timer->tmr_subdevice = tid->subdevice; if (id) strlcpy(timer->id, id, sizeof(timer->id)); INIT_LIST_HEAD(&timer->device_list); INIT_LIST_HEAD(&timer->open_list_head); INIT_LIST_HEAD(&timer->active_list_head); INIT_LIST_HEAD(&timer->ack_list_head); INIT_LIST_HEAD(&timer->sack_list_head); spin_lock_init(&timer->lock); tasklet_init(&timer->task_queue, snd_timer_tasklet, (unsigned long)timer); if (card != NULL) { if ((err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops)) < 0) { snd_timer_free(timer); return err; } } *rtimer = timer; return 0;}static int snd_timer_free(snd_timer_t *timer){ snd_assert(timer != NULL, return -ENXIO); if (timer->private_free) timer->private_free(timer); kfree(timer); return 0;}int snd_timer_dev_free(snd_device_t *device){ 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 = dev->device_data; snd_timer_t *timer1; struct list_head *p; snd_assert(timer != NULL && timer->hw.start != NULL && timer->hw.stop != NULL, return -ENXIO); if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) && !timer->hw.resolution && timer->hw.c_resolution == NULL) return -EINVAL; down(®ister_mutex); list_for_each(p, &snd_timer_list) { timer1 = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); if (timer1->tmr_class > timer->tmr_class) break; if (timer1->tmr_class < timer->tmr_class) continue; if (timer1->card && timer->card) { if (timer1->card->number > timer->card->number) break; if (timer1->card->number < timer->card->number) continue; } if (timer1->tmr_device > timer->tmr_device) break; if (timer1->tmr_device < timer->tmr_device) continue; if (timer1->tmr_subdevice > timer->tmr_subdevice) break; if (timer1->tmr_subdevice < timer->tmr_subdevice) continue; /* conflicts.. */ up(®ister_mutex); return -EBUSY; } list_add_tail(&timer->device_list, p); up(®ister_mutex); return 0;}int snd_timer_unregister(snd_timer_t *timer){ struct list_head *p, *n; snd_timer_instance_t *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 = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list); ti->timer = NULL; } } list_del(&timer->device_list); up(®ister_mutex); return snd_timer_free(timer);}static int snd_timer_dev_unregister(snd_device_t *device){ snd_timer_t *timer = device->device_data; return snd_timer_unregister(timer);}void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct timespec *tstamp){ unsigned long flags; unsigned long resolution = 0; snd_timer_instance_t *ti, *ts; struct list_head *p, *n; snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return); snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return); spin_lock_irqsave(&timer->lock, flags); if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE) { if (timer->hw.c_resolution) resolution = timer->hw.c_resolution(timer); else resolution = timer->hw.resolution; } list_for_each(p, &timer->active_list_head) { ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list); if (ti->ccallback) ti->ccallback(ti, event, tstamp, resolution); list_for_each(n, &ti->slave_active_head) { ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list); if (ts->ccallback) ts->ccallback(ts, event, tstamp, resolution); } } spin_unlock_irqrestore(&timer->lock, flags);}/* * exported functions for global timers */int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer){ snd_timer_id_t tid; tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.card = -1; tid.device = device; tid.subdevice = 0; return snd_timer_new(NULL, id, &tid, rtimer);}int snd_timer_global_free(snd_timer_t *timer){ return snd_timer_free(timer);}int snd_timer_global_register(snd_timer_t *timer){ snd_device_t dev; memset(&dev, 0, sizeof(dev)); dev.device_data = timer; return snd_timer_dev_register(&dev);}int snd_timer_global_unregister(snd_timer_t *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;};unsigned int snd_timer_system_resolution(void){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?