⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 timer.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	.stop =		snd_timer_s_stop};static void snd_timer_free_system(struct snd_timer *timer){	kfree(timer->private_data);}static int snd_timer_register_system(void){	struct snd_timer *timer;	struct snd_timer_system_private *priv;	int err;	err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer);	if (err < 0)		return err;	strcpy(timer->name, "system timer");	timer->hw = snd_timer_system;	priv = kzalloc(sizeof(*priv), GFP_KERNEL);	if (priv == NULL) {		snd_timer_free(timer);		return -ENOMEM;	}	init_timer(&priv->tlist);	priv->tlist.function = snd_timer_s_function;	priv->tlist.data = (unsigned long) timer;	timer->private_data = priv;	timer->private_free = snd_timer_free_system;	return snd_timer_global_register(timer);}#ifdef CONFIG_PROC_FS/* *  Info interface */static void snd_timer_proc_read(struct snd_info_entry *entry,				struct snd_info_buffer *buffer){	struct snd_timer *timer;	struct snd_timer_instance *ti;	mutex_lock(&register_mutex);	list_for_each_entry(timer, &snd_timer_list, device_list) {		switch (timer->tmr_class) {		case SNDRV_TIMER_CLASS_GLOBAL:			snd_iprintf(buffer, "G%i: ", timer->tmr_device);			break;		case SNDRV_TIMER_CLASS_CARD:			snd_iprintf(buffer, "C%i-%i: ",				    timer->card->number, timer->tmr_device);			break;		case SNDRV_TIMER_CLASS_PCM:			snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number,				    timer->tmr_device, timer->tmr_subdevice);			break;		default:			snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class,				    timer->card ? timer->card->number : -1,				    timer->tmr_device, timer->tmr_subdevice);		}		snd_iprintf(buffer, "%s :", timer->name);		if (timer->hw.resolution)			snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",				    timer->hw.resolution / 1000,				    timer->hw.resolution % 1000,				    timer->hw.ticks);		if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)			snd_iprintf(buffer, " SLAVE");		snd_iprintf(buffer, "\n");		list_for_each_entry(ti, &timer->open_list_head, open_list)			snd_iprintf(buffer, "  Client %s : %s\n",				    ti->owner ? ti->owner : "unknown",				    ti->flags & (SNDRV_TIMER_IFLG_START |						 SNDRV_TIMER_IFLG_RUNNING)				    ? "running" : "stopped");	}	mutex_unlock(&register_mutex);}static struct snd_info_entry *snd_timer_proc_entry;static void __init snd_timer_proc_init(void){	struct snd_info_entry *entry;	entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL);	if (entry != NULL) {		entry->c.text.read = snd_timer_proc_read;		if (snd_info_register(entry) < 0) {			snd_info_free_entry(entry);			entry = NULL;		}	}	snd_timer_proc_entry = entry;}static void __exit snd_timer_proc_done(void){	snd_info_free_entry(snd_timer_proc_entry);}#else /* !CONFIG_PROC_FS */#define snd_timer_proc_init()#define snd_timer_proc_done()#endif/* *  USER SPACE interface */static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,				     unsigned long resolution,				     unsigned long ticks){	struct snd_timer_user *tu = timeri->callback_data;	struct snd_timer_read *r;	int prev;	spin_lock(&tu->qlock);	if (tu->qused > 0) {		prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;		r = &tu->queue[prev];		if (r->resolution == resolution) {			r->ticks += ticks;			goto __wake;		}	}	if (tu->qused >= tu->queue_size) {		tu->overrun++;	} else {		r = &tu->queue[tu->qtail++];		tu->qtail %= tu->queue_size;		r->resolution = resolution;		r->ticks = ticks;		tu->qused++;	}      __wake:	spin_unlock(&tu->qlock);	kill_fasync(&tu->fasync, SIGIO, POLL_IN);	wake_up(&tu->qchange_sleep);}static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu,					    struct snd_timer_tread *tread){	if (tu->qused >= tu->queue_size) {		tu->overrun++;	} else {		memcpy(&tu->tqueue[tu->qtail++], tread, sizeof(*tread));		tu->qtail %= tu->queue_size;		tu->qused++;	}}static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,				     int event,				     struct timespec *tstamp,				     unsigned long resolution){	struct snd_timer_user *tu = timeri->callback_data;	struct snd_timer_tread r1;	if (event >= SNDRV_TIMER_EVENT_START &&	    event <= SNDRV_TIMER_EVENT_PAUSE)		tu->tstamp = *tstamp;	if ((tu->filter & (1 << event)) == 0 || !tu->tread)		return;	r1.event = event;	r1.tstamp = *tstamp;	r1.val = resolution;	spin_lock(&tu->qlock);	snd_timer_user_append_to_tqueue(tu, &r1);	spin_unlock(&tu->qlock);	kill_fasync(&tu->fasync, SIGIO, POLL_IN);	wake_up(&tu->qchange_sleep);}static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,				      unsigned long resolution,				      unsigned long ticks){	struct snd_timer_user *tu = timeri->callback_data;	struct snd_timer_tread *r, r1;	struct timespec tstamp;	int prev, append = 0;	memset(&tstamp, 0, sizeof(tstamp));	spin_lock(&tu->qlock);	if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |			   (1 << SNDRV_TIMER_EVENT_TICK))) == 0) {		spin_unlock(&tu->qlock);		return;	}	if (tu->last_resolution != resolution || ticks > 0)		getnstimeofday(&tstamp);	if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&	    tu->last_resolution != resolution) {		r1.event = SNDRV_TIMER_EVENT_RESOLUTION;		r1.tstamp = tstamp;		r1.val = resolution;		snd_timer_user_append_to_tqueue(tu, &r1);		tu->last_resolution = resolution;		append++;	}	if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)		goto __wake;	if (ticks == 0)		goto __wake;	if (tu->qused > 0) {		prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;		r = &tu->tqueue[prev];		if (r->event == SNDRV_TIMER_EVENT_TICK) {			r->tstamp = tstamp;			r->val += ticks;			append++;			goto __wake;		}	}	r1.event = SNDRV_TIMER_EVENT_TICK;	r1.tstamp = tstamp;	r1.val = ticks;	snd_timer_user_append_to_tqueue(tu, &r1);	append++;      __wake:	spin_unlock(&tu->qlock);	if (append == 0)		return;	kill_fasync(&tu->fasync, SIGIO, POLL_IN);	wake_up(&tu->qchange_sleep);}static int snd_timer_user_open(struct inode *inode, struct file *file){	struct snd_timer_user *tu;	tu = kzalloc(sizeof(*tu), GFP_KERNEL);	if (tu == NULL)		return -ENOMEM;	spin_lock_init(&tu->qlock);	init_waitqueue_head(&tu->qchange_sleep);	mutex_init(&tu->tread_sem);	tu->ticks = 1;	tu->queue_size = 128;	tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),			    GFP_KERNEL);	if (tu->queue == NULL) {		kfree(tu);		return -ENOMEM;	}	file->private_data = tu;	return 0;}static int snd_timer_user_release(struct inode *inode, struct file *file){	struct snd_timer_user *tu;	if (file->private_data) {		tu = file->private_data;		file->private_data = NULL;		fasync_helper(-1, file, 0, &tu->fasync);		if (tu->timeri)			snd_timer_close(tu->timeri);		kfree(tu->queue);		kfree(tu->tqueue);		kfree(tu);	}	return 0;}static void snd_timer_user_zero_id(struct snd_timer_id *id){	id->dev_class = SNDRV_TIMER_CLASS_NONE;	id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;	id->card = -1;	id->device = -1;	id->subdevice = -1;}static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *timer){	id->dev_class = timer->tmr_class;	id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;	id->card = timer->card ? timer->card->number : -1;	id->device = timer->tmr_device;	id->subdevice = timer->tmr_subdevice;}static int snd_timer_user_next_device(struct snd_timer_id __user *_tid){	struct snd_timer_id id;	struct snd_timer *timer;	struct list_head *p;	if (copy_from_user(&id, _tid, sizeof(id)))		return -EFAULT;	mutex_lock(&register_mutex);	if (id.dev_class < 0) {		/* first item */		if (list_empty(&snd_timer_list))			snd_timer_user_zero_id(&id);		else {			timer = list_entry(snd_timer_list.next,					   struct snd_timer, device_list);			snd_timer_user_copy_id(&id, timer);		}	} else {		switch (id.dev_class) {		case SNDRV_TIMER_CLASS_GLOBAL:			id.device = id.device < 0 ? 0 : id.device + 1;			list_for_each(p, &snd_timer_list) {				timer = list_entry(p, struct snd_timer, device_list);				if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) {					snd_timer_user_copy_id(&id, timer);					break;				}				if (timer->tmr_device >= id.device) {					snd_timer_user_copy_id(&id, timer);					break;				}			}			if (p == &snd_timer_list)				snd_timer_user_zero_id(&id);			break;		case SNDRV_TIMER_CLASS_CARD:		case SNDRV_TIMER_CLASS_PCM:			if (id.card < 0) {				id.card = 0;			} else {				if (id.card < 0) {					id.card = 0;				} else {					if (id.device < 0) {						id.device = 0;					} else {						if (id.subdevice < 0) {							id.subdevice = 0;						} else {							id.subdevice++;						}					}				}			}			list_for_each(p, &snd_timer_list) {				timer = list_entry(p, struct snd_timer, device_list);				if (timer->tmr_class > id.dev_class) {					snd_timer_user_copy_id(&id, timer);					break;				}				if (timer->tmr_class < id.dev_class)					continue;				if (timer->card->number > id.card) {					snd_timer_user_copy_id(&id, timer);					break;				}				if (timer->card->number < id.card)					continue;				if (timer->tmr_device > id.device) {					snd_timer_user_copy_id(&id, timer);					break;				}				if (timer->tmr_device < id.device)					continue;				if (timer->tmr_subdevice > id.subdevice) {					snd_timer_user_copy_id(&id, timer);					break;				}				if (timer->tmr_subdevice < id.subdevice)					continue;				snd_timer_user_copy_id(&id, timer);				break;			}			if (p == &snd_timer_list)				snd_timer_user_zero_id(&id);			break;		default:			snd_timer_user_zero_id(&id);		}	}	mutex_unlock(&register_mutex);	if (copy_to_user(_tid, &id, sizeof(*_tid)))		return -EFAULT;	return 0;}static int snd_timer_user_ginfo(struct file *file,				struct snd_timer_ginfo __user *_ginfo){	struct snd_timer_ginfo *ginfo;	struct snd_timer_id tid;	struct snd_timer *t;	struct list_head *p;	int err = 0;	ginfo = kmalloc(sizeof(*ginfo), GFP_KERNEL);	if (! ginfo)		return -ENOMEM;	if (copy_from_user(ginfo, _ginfo, sizeof(*ginfo))) {		kfree(ginfo);		return -EFAULT;	}	tid = ginfo->tid;	memset(ginfo, 0, sizeof(*ginfo));	ginfo->tid = tid;	mutex_lock(&register_mutex);	t = snd_timer_find(&tid);	if (t != NULL) {		ginfo->card = t->card ? t->card->number : -1;		if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)			ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;		strlcpy(ginfo->id, t->id, sizeof(ginfo->id));		strlcpy(ginfo->name, t->name, sizeof(ginfo->name));		ginfo->resolution = t->hw.resolution;		if (t->hw.resolution_min > 0) {			ginfo->resolution_min = t->hw.resolution_min;			ginfo->resolution_max = t->hw.resolution_max;		}		list_for_each(p, &t->open_list_head) {			ginfo->clients++;		}	} else {		err = -ENODEV;	}	mutex_unlock(&register_mutex);	if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))		err = -EFAULT;	kfree(ginfo);	return err;}static int snd_timer_user_gparams(struct file *file,				  struct snd_timer_gparams __user *_gparams){	struct snd_timer_gparams gparams;	struct snd_timer *t;	int err;	if (copy_from_user(&gparams, _gparams, sizeof(gparams)))		return -EFAULT;	mutex_lock(&register_mutex);	t = snd_timer_find(&gparams.tid);	if (!t) {		err = -ENODEV;		goto _error;	}	if (!list_empty(&t->open_list_head)) {		err = -EBUSY;		goto _error;	}	if (!t->hw.set_period) {		err = -ENOSYS;		goto _error;	}	err = t->hw.set_period(t, gparams.period_num, gparams.period_den);_error:	mutex_unlock(&register_mutex);	return err;}static int snd_timer_user_gstatus(struct file *file,				  struct snd_timer_gstatus __user *_gstatus){	struct snd_timer_gstatus gstatus;	struct snd_timer_id tid;	struct snd_timer *t;	int err = 0;	if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus)))		return -EFAULT;	tid = gstatus.tid;	memset(&gstatus, 0, sizeof(gstatus));	gstatus.tid = tid;	mutex_lock(&register_mutex);	t = snd_timer_find(&tid);	if (t != NULL) {		if (t->hw.c_resolution)			gstatus.resolution = t->hw.c_resolution(t);		else			gstatus.resolution = t->hw.resolution;		if (t->hw.precise_resolution) {			t->hw.precise_resolution(t, &gstatus.resolution_num,						 &gstatus.resolution_den);		} else {			gstatus.resolution_num = gstatus.resolution;			gstatus.resolution_den = 1000000000uL;		}	} else {		err = -ENODEV;	}	mutex_unlock(&register_mutex);	if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))		err = -EFAULT;	return err;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -