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(&register_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(&register_mutex);		return -EBUSY;	}	list_add_tail(&timer->device_list, p);	up(&register_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(&register_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(&register_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 + -
显示快捷键?