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

📄 timer.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static int snd_timer_user_tselect(struct file *file,				  struct snd_timer_select __user *_tselect){	struct snd_timer_user *tu;	struct snd_timer_select tselect;	char str[32];	int err = 0;	tu = file->private_data;	mutex_lock(&tu->tread_sem);	if (tu->timeri) {		snd_timer_close(tu->timeri);		tu->timeri = NULL;	}	if (copy_from_user(&tselect, _tselect, sizeof(tselect))) {		err = -EFAULT;		goto __err;	}	sprintf(str, "application %i", current->pid);	if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)		tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;	err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid);	if (err < 0)		goto __err;	kfree(tu->queue);	tu->queue = NULL;	kfree(tu->tqueue);	tu->tqueue = NULL;	if (tu->tread) {		tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread),				     GFP_KERNEL);		if (tu->tqueue == NULL)			err = -ENOMEM;	} else {		tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),				    GFP_KERNEL);		if (tu->queue == NULL)			err = -ENOMEM;	}      	if (err < 0) {		snd_timer_close(tu->timeri);      		tu->timeri = NULL;      	} else {		tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;		tu->timeri->callback = tu->tread			? snd_timer_user_tinterrupt : snd_timer_user_interrupt;		tu->timeri->ccallback = snd_timer_user_ccallback;		tu->timeri->callback_data = (void *)tu;	}      __err:      	mutex_unlock(&tu->tread_sem);	return err;}static int snd_timer_user_info(struct file *file,			       struct snd_timer_info __user *_info){	struct snd_timer_user *tu;	struct snd_timer_info *info;	struct snd_timer *t;	int err = 0;	tu = file->private_data;	if (!tu->timeri)		return -EBADFD;	t = tu->timeri->timer;	if (!t)		return -EBADFD;	info = kzalloc(sizeof(*info), GFP_KERNEL);	if (! info)		return -ENOMEM;	info->card = t->card ? t->card->number : -1;	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)		info->flags |= SNDRV_TIMER_FLG_SLAVE;	strlcpy(info->id, t->id, sizeof(info->id));	strlcpy(info->name, t->name, sizeof(info->name));	info->resolution = t->hw.resolution;	if (copy_to_user(_info, info, sizeof(*_info)))		err = -EFAULT;	kfree(info);	return err;}static int snd_timer_user_params(struct file *file,				 struct snd_timer_params __user *_params){	struct snd_timer_user *tu;	struct snd_timer_params params;	struct snd_timer *t;	struct snd_timer_read *tr;	struct snd_timer_tread *ttr;	int err;	tu = file->private_data;	if (!tu->timeri)		return -EBADFD;	t = tu->timeri->timer;	if (!t)		return -EBADFD;	if (copy_from_user(&params, _params, sizeof(params)))		return -EFAULT;	if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {		err = -EINVAL;		goto _end;	}	if (params.queue_size > 0 &&	    (params.queue_size < 32 || params.queue_size > 1024)) {		err = -EINVAL;		goto _end;	}	if (params.filter & ~((1<<SNDRV_TIMER_EVENT_RESOLUTION)|			      (1<<SNDRV_TIMER_EVENT_TICK)|			      (1<<SNDRV_TIMER_EVENT_START)|			      (1<<SNDRV_TIMER_EVENT_STOP)|			      (1<<SNDRV_TIMER_EVENT_CONTINUE)|			      (1<<SNDRV_TIMER_EVENT_PAUSE)|			      (1<<SNDRV_TIMER_EVENT_SUSPEND)|			      (1<<SNDRV_TIMER_EVENT_RESUME)|			      (1<<SNDRV_TIMER_EVENT_MSTART)|			      (1<<SNDRV_TIMER_EVENT_MSTOP)|			      (1<<SNDRV_TIMER_EVENT_MCONTINUE)|			      (1<<SNDRV_TIMER_EVENT_MPAUSE)|			      (1<<SNDRV_TIMER_EVENT_MSUSPEND)|			      (1<<SNDRV_TIMER_EVENT_MRESUME))) {		err = -EINVAL;		goto _end;	}	snd_timer_stop(tu->timeri);	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;	if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)		tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;	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 = kmalloc(params.queue_size * sizeof(*ttr),				      GFP_KERNEL);			if (ttr) {				kfree(tu->tqueue);				tu->queue_size = params.queue_size;				tu->tqueue = ttr;			}		} else {			tr = kmalloc(params.queue_size * sizeof(*tr),				     GFP_KERNEL);			if (tr) {				kfree(tu->queue);				tu->queue_size = params.queue_size;				tu->queue = tr;			}		}	}	tu->qhead = tu->qtail = tu->qused = 0;	if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {		if (tu->tread) {			struct snd_timer_tread 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 {			struct snd_timer_read *r = &tu->queue[0];			r->resolution = 0;			r->ticks = 0;			tu->qused++;			tu->qtail++;		}	}	tu->filter = params.filter;	tu->ticks = params.ticks;	err = 0; _end:	if (copy_to_user(_params, &params, sizeof(params)))		return -EFAULT;	return err;}static int snd_timer_user_status(struct file *file,				 struct snd_timer_status __user *_status){	struct snd_timer_user *tu;	struct snd_timer_status status;	tu = file->private_data;	if (!tu->timeri)		return -EBADFD;	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_irq(&tu->qlock);	status.queue = tu->qused;	spin_unlock_irq(&tu->qlock);	if (copy_to_user(_status, &status, sizeof(status)))		return -EFAULT;	return 0;}static int snd_timer_user_start(struct file *file){	int err;	struct snd_timer_user *tu;	tu = file->private_data;	if (!tu->timeri)		return -EBADFD;	snd_timer_stop(tu->timeri);	tu->timeri->lost = 0;	tu->last_resolution = 0;	return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0;}static int snd_timer_user_stop(struct file *file){	int err;	struct snd_timer_user *tu;	tu = file->private_data;	if (!tu->timeri)		return -EBADFD;	return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;}static int snd_timer_user_continue(struct file *file){	int err;	struct snd_timer_user *tu;	tu = file->private_data;	if (!tu->timeri)		return -EBADFD;	tu->timeri->lost = 0;	return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;}static int snd_timer_user_pause(struct file *file){	int err;	struct snd_timer_user *tu;	tu = file->private_data;	if (!tu->timeri)		return -EBADFD;	return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;}enum {	SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20),	SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21),	SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22),	SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),};static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,				 unsigned long arg){	struct snd_timer_user *tu;	void __user *argp = (void __user *)arg;	int __user *p = argp;	tu = file->private_data;	switch (cmd) {	case SNDRV_TIMER_IOCTL_PVERSION:		return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0;	case SNDRV_TIMER_IOCTL_NEXT_DEVICE:		return snd_timer_user_next_device(argp);	case SNDRV_TIMER_IOCTL_TREAD:	{		int xarg;		mutex_lock(&tu->tread_sem);		if (tu->timeri)	{	/* too late */			mutex_unlock(&tu->tread_sem);			return -EBUSY;		}		if (get_user(xarg, p)) {			mutex_unlock(&tu->tread_sem);			return -EFAULT;		}		tu->tread = xarg ? 1 : 0;		mutex_unlock(&tu->tread_sem);		return 0;	}	case SNDRV_TIMER_IOCTL_GINFO:		return snd_timer_user_ginfo(file, argp);	case SNDRV_TIMER_IOCTL_GPARAMS:		return snd_timer_user_gparams(file, argp);	case SNDRV_TIMER_IOCTL_GSTATUS:		return snd_timer_user_gstatus(file, argp);	case SNDRV_TIMER_IOCTL_SELECT:		return snd_timer_user_tselect(file, argp);	case SNDRV_TIMER_IOCTL_INFO:		return snd_timer_user_info(file, argp);	case SNDRV_TIMER_IOCTL_PARAMS:		return snd_timer_user_params(file, argp);	case SNDRV_TIMER_IOCTL_STATUS:		return snd_timer_user_status(file, argp);	case SNDRV_TIMER_IOCTL_START:	case SNDRV_TIMER_IOCTL_START_OLD:		return snd_timer_user_start(file);	case SNDRV_TIMER_IOCTL_STOP:	case SNDRV_TIMER_IOCTL_STOP_OLD:		return snd_timer_user_stop(file);	case SNDRV_TIMER_IOCTL_CONTINUE:	case SNDRV_TIMER_IOCTL_CONTINUE_OLD:		return snd_timer_user_continue(file);	case SNDRV_TIMER_IOCTL_PAUSE:	case SNDRV_TIMER_IOCTL_PAUSE_OLD:		return snd_timer_user_pause(file);	}	return -ENOTTY;}static int snd_timer_user_fasync(int fd, struct file * file, int on){	struct snd_timer_user *tu;	int err;	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 __user *buffer,				   size_t count, loff_t *offset){	struct snd_timer_user *tu;	long result = 0, unit;	int err = 0;	tu = file->private_data;	unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read);	spin_lock_irq(&tu->qlock);	while ((long)count - result >= unit) {		while (!tu->qused) {			wait_queue_t wait;			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {				err = -EAGAIN;				break;			}			set_current_state(TASK_INTERRUPTIBLE);			init_waitqueue_entry(&wait, current);			add_wait_queue(&tu->qchange_sleep, &wait);			spin_unlock_irq(&tu->qlock);			schedule();			spin_lock_irq(&tu->qlock);			remove_wait_queue(&tu->qchange_sleep, &wait);			if (signal_pending(current)) {				err = -ERESTARTSYS;				break;			}		}		spin_unlock_irq(&tu->qlock);		if (err < 0)			goto _error;		if (tu->tread) {			if (copy_to_user(buffer, &tu->tqueue[tu->qhead++],					 sizeof(struct snd_timer_tread))) {				err = -EFAULT;				goto _error;			}		} else {			if (copy_to_user(buffer, &tu->queue[tu->qhead++],					 sizeof(struct snd_timer_read))) {				err = -EFAULT;				goto _error;			}		}		tu->qhead %= tu->queue_size;		result += unit;		buffer += unit;		spin_lock_irq(&tu->qlock);		tu->qused--;	}	spin_unlock_irq(&tu->qlock); _error:	return result > 0 ? result : err;}static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait){        unsigned int mask;        struct snd_timer_user *tu;        tu = file->private_data;        poll_wait(file, &tu->qchange_sleep, wait);	mask = 0;	if (tu->qused)		mask |= POLLIN | POLLRDNORM;	return mask;}#ifdef CONFIG_COMPAT#include "timer_compat.c"#else#define snd_timer_user_ioctl_compat	NULL#endifstatic const struct file_operations snd_timer_f_ops ={	.owner =	THIS_MODULE,	.read =		snd_timer_user_read,	.open =		snd_timer_user_open,	.release =	snd_timer_user_release,	.poll =		snd_timer_user_poll,	.unlocked_ioctl =	snd_timer_user_ioctl,	.compat_ioctl =	snd_timer_user_ioctl_compat,	.fasync = 	snd_timer_user_fasync,};/* *  ENTRY functions */static int __init alsa_timer_init(void){	int err;#ifdef SNDRV_OSS_INFO_DEV_TIMERS	snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1,			      "system timer");#endif	if ((err = snd_timer_register_system()) < 0)		snd_printk(KERN_ERR "unable to register system timer (%i)\n",			   err);	if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,				       &snd_timer_f_ops, NULL, "timer")) < 0)		snd_printk(KERN_ERR "unable to register timer device (%i)\n",			   err);	snd_timer_proc_init();	return 0;}static void __exit alsa_timer_exit(void){	struct list_head *p, *n;	snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0);	/* unregister the system timer */	list_for_each_safe(p, n, &snd_timer_list) {		struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);		snd_timer_free(timer);	}	snd_timer_proc_done();#ifdef SNDRV_OSS_INFO_DEV_TIMERS	snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);#endif}module_init(alsa_timer_init)module_exit(alsa_timer_exit)EXPORT_SYMBOL(snd_timer_open);EXPORT_SYMBOL(snd_timer_close);EXPORT_SYMBOL(snd_timer_resolution);EXPORT_SYMBOL(snd_timer_start);EXPORT_SYMBOL(snd_timer_stop);EXPORT_SYMBOL(snd_timer_continue);EXPORT_SYMBOL(snd_timer_pause);EXPORT_SYMBOL(snd_timer_new);EXPORT_SYMBOL(snd_timer_notify);EXPORT_SYMBOL(snd_timer_global_new);EXPORT_SYMBOL(snd_timer_global_free);EXPORT_SYMBOL(snd_timer_global_register);EXPORT_SYMBOL(snd_timer_interrupt);

⌨️ 快捷键说明

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