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

📄 control.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	kctl.count = info.owner ? info.owner : 1;	access |= SNDRV_CTL_ELEM_ACCESS_USER;	kctl.info = snd_ctl_elem_user_info;	if (access & SNDRV_CTL_ELEM_ACCESS_READ)		kctl.get = snd_ctl_elem_user_get;	if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)		kctl.put = snd_ctl_elem_user_put;	extra_size = 0;	switch (info.type) {	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:		private_size = sizeof(char);		if (info.count > 128)			return -EINVAL;		break;	case SNDRV_CTL_ELEM_TYPE_INTEGER:		private_size = sizeof(long);		if (info.count > 128)			return -EINVAL;		break;	case SNDRV_CTL_ELEM_TYPE_INTEGER64:		private_size = sizeof(long long);		if (info.count > 64)			return -EINVAL;		break;	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:		private_size = sizeof(unsigned int);		if (info.count > 128)			return -EINVAL;		if (info.value.enumerated.items > 1024)			return -EINVAL;		extra_size = info.value.enumerated.items * 64;		break;	case SNDRV_CTL_ELEM_TYPE_BYTES:		private_size = sizeof(unsigned char);		if (info.count > 512)			return -EINVAL;		break;	case SNDRV_CTL_ELEM_TYPE_IEC958:		private_size = sizeof(struct sndrv_aes_iec958);		if (info.count != 1)			return -EINVAL;		break;	default:		return -EINVAL;	}	private_size *= info.count;	if (private_size > 1024 * 1024)		return -EINVAL;	dimen_size = 0;	if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT))		for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++)			dimen_size += sizeof(unsigned short);	ue = kcalloc(1, sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL);	if (ue == NULL)		return -ENOMEM;	ue->type = info.type;	ue->elem_count = info.count;	if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT)) {		for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++)			ue->dimen[idx] = info.dimen.d[idx];		ue->dimen_count = dimen_size / sizeof(unsigned short);	}	ue->elem_data = (char *)ue + sizeof(ue) + dimen_size;	ue->elem_data_size = private_size;	if (extra_size) {		ue->priv_data = (char *)ue + sizeof(ue) + dimen_size + private_size;		ue->priv_data_size = extra_size;		if (ue->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {			if (copy_from_user(ue->priv_data, *(char **)info.value.enumerated.name, extra_size))				return -EFAULT;			ue->u.enumerated.items = info.value.enumerated.items;		}	}	kctl.private_free = snd_ctl_elem_user_free;	_kctl = snd_ctl_new(&kctl, access);	if (_kctl == NULL) {		kfree(_kctl->private_data);		return -ENOMEM;	}	_kctl->private_data = ue;	for (idx = 0; idx < _kctl->count; idx++)		_kctl->vd[idx].owner = file;	err = snd_ctl_add(card, _kctl);	if (err < 0) {		snd_ctl_free_one(_kctl);		return err;	}	return 0;}static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id){	snd_ctl_elem_id_t id;	if (copy_from_user(&id, _id, sizeof(id)))		return -EFAULT;	return snd_ctl_remove_unlocked_id(file, &id);}static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int __user *ptr){	int subscribe;	if (get_user(subscribe, ptr))		return -EFAULT;	if (subscribe < 0) {		subscribe = file->subscribed;		if (put_user(subscribe, ptr))			return -EFAULT;		return 0;	}	if (subscribe) {		file->subscribed = 1;		return 0;	} else if (file->subscribed) {		snd_ctl_empty_read_queue(file);		file->subscribed = 0;	}	return 0;}#ifdef CONFIG_PM/* * change the power state */static int snd_ctl_set_power_state(snd_card_t *card, unsigned int power_state){	switch (power_state) {	case SNDRV_CTL_POWER_D0:	case SNDRV_CTL_POWER_D1:	case SNDRV_CTL_POWER_D2:		if (card->power_state != power_state)			/* FIXME: pass the correct state value */			card->pm_resume(card, 0);		break;	case SNDRV_CTL_POWER_D3hot:	case SNDRV_CTL_POWER_D3cold:		if (card->power_state != power_state)			/* FIXME: pass the correct state value */			card->pm_suspend(card, 0);		break;	default:		return -EINVAL;	}	return 0;}#endifstatic inline int _snd_ctl_ioctl(struct inode *inode, struct file *file,				 unsigned int cmd, unsigned long arg){	snd_ctl_file_t *ctl;	snd_card_t *card;	struct list_head *list;	snd_kctl_ioctl_t *p;	void __user *argp = (void __user *)arg;	int __user *ip = argp;	int err;	ctl = file->private_data;	card = ctl->card;	snd_assert(card != NULL, return -ENXIO);	switch (cmd) {	case SNDRV_CTL_IOCTL_PVERSION:		return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;	case SNDRV_CTL_IOCTL_CARD_INFO:		return snd_ctl_card_info(card, ctl, cmd, argp);	case SNDRV_CTL_IOCTL_ELEM_LIST:		return snd_ctl_elem_list(ctl->card, argp);	case SNDRV_CTL_IOCTL_ELEM_INFO:		return snd_ctl_elem_info(ctl, argp);	case SNDRV_CTL_IOCTL_ELEM_READ:		return snd_ctl_elem_read(ctl->card, argp);	case SNDRV_CTL_IOCTL_ELEM_WRITE:		return snd_ctl_elem_write(ctl, argp);	case SNDRV_CTL_IOCTL_ELEM_LOCK:		return snd_ctl_elem_lock(ctl, argp);	case SNDRV_CTL_IOCTL_ELEM_UNLOCK:		return snd_ctl_elem_unlock(ctl, argp);	case SNDRV_CTL_IOCTL_ELEM_ADD:		return snd_ctl_elem_add(ctl, argp, 0);	case SNDRV_CTL_IOCTL_ELEM_REPLACE:		return snd_ctl_elem_add(ctl, argp, 1);	case SNDRV_CTL_IOCTL_ELEM_REMOVE:		return snd_ctl_elem_remove(ctl, argp);	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:		return snd_ctl_subscribe_events(ctl, ip);	case SNDRV_CTL_IOCTL_POWER:		if (get_user(err, ip))			return -EFAULT;		if (!capable(CAP_SYS_ADMIN))			return -EPERM;#ifdef CONFIG_PM		if (card->pm_suspend && card->pm_resume) {			snd_power_lock(card);			err = snd_ctl_set_power_state(card, err);			snd_power_unlock(card);		} else#endif			err = -ENOPROTOOPT;		return err;	case SNDRV_CTL_IOCTL_POWER_STATE:#ifdef CONFIG_PM		return put_user(card->power_state, ip) ? -EFAULT : 0;#else		return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;#endif	}	down_read(&snd_ioctl_rwsem);	list_for_each(list, &snd_control_ioctls) {		p = list_entry(list, snd_kctl_ioctl_t, list);		err = p->fioctl(card, ctl, cmd, arg);		if (err != -ENOIOCTLCMD) {			up_read(&snd_ioctl_rwsem);			return err;		}	}	up_read(&snd_ioctl_rwsem);	snd_printd("unknown ioctl = 0x%x\n", cmd);	return -ENOTTY;}/* FIXME: need to unlock BKL to allow preemption */static int snd_ctl_ioctl(struct inode *inode, struct file *file,			 unsigned int cmd, unsigned long arg){	int err;	unlock_kernel();	err = _snd_ctl_ioctl(inode, file, cmd, arg);	lock_kernel();	return err;}static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset){	snd_ctl_file_t *ctl;	int err = 0;	ssize_t result = 0;	ctl = file->private_data;	snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO);	if (!ctl->subscribed)		return -EBADFD;	if (count < sizeof(snd_ctl_event_t))		return -EINVAL;	spin_lock_irq(&ctl->read_lock);	while (count >= sizeof(snd_ctl_event_t)) {		snd_ctl_event_t ev;		snd_kctl_event_t *kev;		while (list_empty(&ctl->events)) {			wait_queue_t wait;			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {				err = -EAGAIN;				goto __end_lock;			}			init_waitqueue_entry(&wait, current);			add_wait_queue(&ctl->change_sleep, &wait);			set_current_state(TASK_INTERRUPTIBLE);			spin_unlock_irq(&ctl->read_lock);			schedule();			remove_wait_queue(&ctl->change_sleep, &wait);			if (signal_pending(current))				return result > 0 ? result : -ERESTARTSYS;			spin_lock_irq(&ctl->read_lock);		}		kev = snd_kctl_event(ctl->events.next);		ev.type = SNDRV_CTL_EVENT_ELEM;		ev.data.elem.mask = kev->mask;		ev.data.elem.id = kev->id;		list_del(&kev->list);		spin_unlock_irq(&ctl->read_lock);		kfree(kev);		if (copy_to_user(buffer, &ev, sizeof(snd_ctl_event_t))) {			err = -EFAULT;			goto __end;		}		spin_lock_irq(&ctl->read_lock);		buffer += sizeof(snd_ctl_event_t);		count -= sizeof(snd_ctl_event_t);		result += sizeof(snd_ctl_event_t);	}      __end_lock:	spin_unlock_irq(&ctl->read_lock);      __end:      	return result > 0 ? result : err;}static unsigned int snd_ctl_poll(struct file *file, poll_table * wait){	unsigned int mask;	snd_ctl_file_t *ctl;	ctl = file->private_data;	if (!ctl->subscribed)		return 0;	poll_wait(file, &ctl->change_sleep, wait);	mask = 0;	if (!list_empty(&ctl->events))		mask |= POLLIN | POLLRDNORM;	return mask;}/* * register the device-specific control-ioctls. * called from each device manager like pcm.c, hwdep.c, etc. */int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn){	snd_kctl_ioctl_t *pn;	pn = kcalloc(1, sizeof(snd_kctl_ioctl_t), GFP_KERNEL);	if (pn == NULL)		return -ENOMEM;	pn->fioctl = fcn;	down_write(&snd_ioctl_rwsem);	list_add_tail(&pn->list, &snd_control_ioctls);	up_write(&snd_ioctl_rwsem);	return 0;}/* * de-register the device-specific control-ioctls. */int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn){	struct list_head *list;	snd_kctl_ioctl_t *p;	snd_runtime_check(fcn != NULL, return -EINVAL);	down_write(&snd_ioctl_rwsem);	list_for_each(list, &snd_control_ioctls) {		p = list_entry(list, snd_kctl_ioctl_t, list);		if (p->fioctl == fcn) {			list_del(&p->list);			up_write(&snd_ioctl_rwsem);			kfree(p);			return 0;		}	}	up_write(&snd_ioctl_rwsem);	snd_BUG();	return -EINVAL;}static int snd_ctl_fasync(int fd, struct file * file, int on){	snd_ctl_file_t *ctl;	int err;	ctl = file->private_data;	err = fasync_helper(fd, file, on, &ctl->fasync);	if (err < 0)		return err;	return 0;}/* *  INIT PART */static struct file_operations snd_ctl_f_ops ={	.owner =	THIS_MODULE,	.read =		snd_ctl_read,	.open =		snd_ctl_open,	.release =	snd_ctl_release,	.poll =		snd_ctl_poll,	.ioctl =	snd_ctl_ioctl,	.fasync =	snd_ctl_fasync,};static snd_minor_t snd_ctl_reg ={	.comment =	"ctl",	.f_ops =	&snd_ctl_f_ops,};/* * registration of the control device: * called from init.c */int snd_ctl_register(snd_card_t *card){	int err, cardnum;	char name[16];	snd_assert(card != NULL, return -ENXIO);	cardnum = card->number;	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);	sprintf(name, "controlC%i", cardnum);	if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL,					card, 0, &snd_ctl_reg, name)) < 0)		return err;	return 0;}/* * disconnection of the control device: * called from init.c */int snd_ctl_disconnect(snd_card_t *card){	struct list_head *flist;	snd_ctl_file_t *ctl;	down_read(&card->controls_rwsem);	list_for_each(flist, &card->ctl_files) {		ctl = snd_ctl_file(flist);		wake_up(&ctl->change_sleep);		kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);	}	up_read(&card->controls_rwsem);	return 0;}/* * de-registration of the control device: * called from init.c */int snd_ctl_unregister(snd_card_t *card){	int err, cardnum;	snd_kcontrol_t *control;	snd_assert(card != NULL, return -ENXIO);	cardnum = card->number;	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);	if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, card, 0)) < 0)		return err;	down_write(&card->controls_rwsem);	while (!list_empty(&card->controls)) {		control = snd_kcontrol(card->controls.next);		snd_ctl_remove(card, control);	}	up_write(&card->controls_rwsem);	return 0;}

⌨️ 快捷键说明

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