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

📄 control.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Routines for driver control interface *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> * * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */#include <sound/driver.h>#include <linux/threads.h>#include <linux/interrupt.h>#include <linux/smp_lock.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/time.h>#include <sound/core.h>#include <sound/minors.h>#include <sound/info.h>#include <sound/control.h>typedef struct _snd_kctl_ioctl {	struct list_head list;		/* list of all ioctls */	snd_kctl_ioctl_func_t fioctl;} snd_kctl_ioctl_t;#define snd_kctl_ioctl(n) list_entry(n, snd_kctl_ioctl_t, list)static DECLARE_RWSEM(snd_ioctl_rwsem);static LIST_HEAD(snd_control_ioctls);static int snd_ctl_open(struct inode *inode, struct file *file){	int cardnum = SNDRV_MINOR_CARD(iminor(inode));	unsigned long flags;	snd_card_t *card;	snd_ctl_file_t *ctl;	int err;	card = snd_cards[cardnum];	if (!card) {		err = -ENODEV;		goto __error1;	}	err = snd_card_file_add(card, file);	if (err < 0) {		err = -ENODEV;		goto __error1;	}	if (!try_module_get(card->module)) {		err = -EFAULT;		goto __error2;	}	ctl = kcalloc(1, sizeof(*ctl), GFP_KERNEL);	if (ctl == NULL) {		err = -ENOMEM;		goto __error;	}	INIT_LIST_HEAD(&ctl->events);	init_waitqueue_head(&ctl->change_sleep);	spin_lock_init(&ctl->read_lock);	ctl->card = card;	ctl->pid = current->pid;	file->private_data = ctl;	write_lock_irqsave(&card->ctl_files_rwlock, flags);	list_add_tail(&ctl->list, &card->ctl_files);	write_unlock_irqrestore(&card->ctl_files_rwlock, flags);	return 0;      __error:	module_put(card->module);      __error2:	snd_card_file_remove(card, file);      __error1:      	return err;}static void snd_ctl_empty_read_queue(snd_ctl_file_t * ctl){	snd_kctl_event_t *cread;		spin_lock(&ctl->read_lock);	while (!list_empty(&ctl->events)) {		cread = snd_kctl_event(ctl->events.next);		list_del(&cread->list);		kfree(cread);	}	spin_unlock(&ctl->read_lock);}static int snd_ctl_release(struct inode *inode, struct file *file){	unsigned long flags;	struct list_head *list;	snd_card_t *card;	snd_ctl_file_t *ctl;	snd_kcontrol_t *control;	unsigned int idx;	ctl = file->private_data;	fasync_helper(-1, file, 0, &ctl->fasync);	file->private_data = NULL;	card = ctl->card;	write_lock_irqsave(&card->ctl_files_rwlock, flags);	list_del(&ctl->list);	write_unlock_irqrestore(&card->ctl_files_rwlock, flags);	down_write(&card->controls_rwsem);	list_for_each(list, &card->controls) {		control = snd_kcontrol(list);		for (idx = 0; idx < control->count; idx++)			if (control->vd[idx].owner == ctl)				control->vd[idx].owner = NULL;	}	up_write(&card->controls_rwsem);	snd_ctl_empty_read_queue(ctl);	kfree(ctl);	module_put(card->module);	snd_card_file_remove(card, file);	return 0;}void snd_ctl_notify(snd_card_t *card, unsigned int mask, snd_ctl_elem_id_t *id){	unsigned long flags;	struct list_head *flist;	snd_ctl_file_t *ctl;	snd_kctl_event_t *ev;		snd_runtime_check(card != NULL && id != NULL, return);	read_lock(&card->ctl_files_rwlock);#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)	card->mixer_oss_change_count++;#endif	list_for_each(flist, &card->ctl_files) {		struct list_head *elist;		ctl = snd_ctl_file(flist);		if (!ctl->subscribed)			continue;		spin_lock_irqsave(&ctl->read_lock, flags);		list_for_each(elist, &ctl->events) {			ev = snd_kctl_event(elist);			if (ev->id.numid == id->numid) {				ev->mask |= mask;				goto _found;			}		}		ev = kcalloc(1, sizeof(*ev), GFP_ATOMIC);		if (ev) {			ev->id = *id;			ev->mask = mask;			list_add_tail(&ev->list, &ctl->events);		} else {			snd_printk(KERN_ERR "No memory available to allocate event\n");		}	_found:		wake_up(&ctl->change_sleep);		spin_unlock_irqrestore(&ctl->read_lock, flags);		kill_fasync(&ctl->fasync, SIGIO, POLL_IN);	}	read_unlock(&card->ctl_files_rwlock);}/** * snd_ctl_new - create a control instance from the template * @control: the control template * @access: the default control access * * Allocates a new snd_kcontrol_t instance and copies the given template  * to the new instance. It does not copy volatile data (access). * * Returns the pointer of the new instance, or NULL on failure. */snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access){	snd_kcontrol_t *kctl;	unsigned int idx;		snd_runtime_check(control != NULL, return NULL);	snd_runtime_check(control->count > 0, return NULL);	kctl = kcalloc(1, sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL);	if (kctl == NULL)		return NULL;	*kctl = *control;	for (idx = 0; idx < kctl->count; idx++)		kctl->vd[idx].access = access;	return kctl;}/** * snd_ctl_new1 - create a control instance from the template * @ncontrol: the initialization record * @private_data: the private data to set * * Allocates a new snd_kcontrol_t instance and initialize from the given  * template.  When the access field of ncontrol is 0, it's assumed as * READWRITE access. When the count field is 0, it's assumes as one. * * Returns the pointer of the newly generated instance, or NULL on failure. */snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data){	snd_kcontrol_t kctl;	unsigned int access;		snd_runtime_check(ncontrol != NULL, return NULL);	snd_assert(ncontrol->info != NULL, return NULL);	memset(&kctl, 0, sizeof(kctl));	kctl.id.iface = ncontrol->iface;	kctl.id.device = ncontrol->device;	kctl.id.subdevice = ncontrol->subdevice;	if (ncontrol->name)		strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));	kctl.id.index = ncontrol->index;	kctl.count = ncontrol->count ? ncontrol->count : 1;	access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :		 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE|		 		      SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT));	kctl.info = ncontrol->info;	kctl.get = ncontrol->get;	kctl.put = ncontrol->put;	kctl.private_value = ncontrol->private_value;	kctl.private_data = private_data;	return snd_ctl_new(&kctl, access);}/** * snd_ctl_free_one - release the control instance * @kcontrol: the control instance * * Releases the control instance created via snd_ctl_new() * or snd_ctl_new1(). * Don't call this after the control was added to the card. */void snd_ctl_free_one(snd_kcontrol_t * kcontrol){	if (kcontrol) {		if (kcontrol->private_free)			kcontrol->private_free(kcontrol);		kfree(kcontrol);	}}static unsigned int snd_ctl_hole_check(snd_card_t * card,				       unsigned int count){	struct list_head *list;	snd_kcontrol_t *kctl;	list_for_each(list, &card->controls) {		kctl = snd_kcontrol(list);		if ((kctl->id.numid <= card->last_numid &&		     kctl->id.numid + kctl->count > card->last_numid) ||		    (kctl->id.numid <= card->last_numid + count - 1 &&		     kctl->id.numid + kctl->count > card->last_numid + count - 1))		    	return card->last_numid = kctl->id.numid + kctl->count - 1;	}	return card->last_numid;}static int snd_ctl_find_hole(snd_card_t * card, unsigned int count){	unsigned int last_numid, iter = 100000;	last_numid = card->last_numid;	while (last_numid != snd_ctl_hole_check(card, count)) {		if (--iter == 0) {			/* this situation is very unlikely */			snd_printk(KERN_ERR "unable to allocate new control numid\n");			return -ENOMEM;		}		last_numid = card->last_numid;	}	return 0;}/** * snd_ctl_add - add the control instance to the card * @card: the card instance * @kcontrol: the control instance to add * * Adds the control instance created via snd_ctl_new() or * snd_ctl_new1() to the given card. Assigns also an unique * numid used for fast search. * * Returns zero if successful, or a negative error code on failure. * * It frees automatically the control which cannot be added. */int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol){	snd_ctl_elem_id_t id;	unsigned int idx;	snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL);	snd_assert(kcontrol->info != NULL, return -EINVAL);	id = kcontrol->id;	down_write(&card->controls_rwsem);	if (snd_ctl_find_id(card, &id)) {		up_write(&card->controls_rwsem);		snd_ctl_free_one(kcontrol);		snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",					id.iface,					id.device,					id.subdevice,					id.name,					id.index);		return -EBUSY;	}	if (snd_ctl_find_hole(card, kcontrol->count) < 0) {		up_write(&card->controls_rwsem);		snd_ctl_free_one(kcontrol);		return -ENOMEM;	}	list_add_tail(&kcontrol->list, &card->controls);	card->controls_count += kcontrol->count;	kcontrol->id.numid = card->last_numid + 1;	card->last_numid += kcontrol->count;	up_write(&card->controls_rwsem);	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);	return 0;}/** * snd_ctl_remove - remove the control from the card and release it * @card: the card instance * @kcontrol: the control instance to remove * * Removes the control from the card and then releases the instance. * You don't need to call snd_ctl_free_one(). You must be in * the write lock - down_write(&card->controls_rwsem). *  * Returns 0 if successful, or a negative error code on failure. */int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol){	snd_ctl_elem_id_t id;	unsigned int idx;	snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL);	list_del(&kcontrol->list);	card->controls_count -= kcontrol->count;	id = kcontrol->id;	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id);	snd_ctl_free_one(kcontrol);	return 0;}/** * snd_ctl_remove_id - remove the control of the given id and release it * @card: the card instance * @id: the control id to remove * * Finds the control instance with the given id, removes it from the * card list and releases it. *  * Returns 0 if successful, or a negative error code on failure. */int snd_ctl_remove_id(snd_card_t * card, snd_ctl_elem_id_t *id){	snd_kcontrol_t *kctl;	int ret;	down_write(&card->controls_rwsem);	kctl = snd_ctl_find_id(card, id);	if (kctl == NULL) {		up_write(&card->controls_rwsem);		return -ENOENT;	}	ret = snd_ctl_remove(card, kctl);	up_write(&card->controls_rwsem);	return ret;}/** * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it * @file: active control handle * @id: the control id to remove * * Finds the control instance with the given id, removes it from the * card list and releases it. *  * Returns 0 if successful, or a negative error code on failure. */static int snd_ctl_remove_unlocked_id(snd_ctl_file_t * file, snd_ctl_elem_id_t *id){	snd_card_t *card = file->card;	snd_kcontrol_t *kctl;	int idx, ret;	down_write(&card->controls_rwsem);	kctl = snd_ctl_find_id(card, id);	if (kctl == NULL) {		up_write(&card->controls_rwsem);		return -ENOENT;	}	for (idx = 0; idx < kctl->count; idx++)		if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {			up_write(&card->controls_rwsem);			return -EBUSY;		}	ret = snd_ctl_remove(card, kctl);	up_write(&card->controls_rwsem);	return ret;}/** * snd_ctl_rename_id - replace the id of a control on the card * @card: the card instance * @src_id: the old id * @dst_id: the new id * * Finds the control with the old id from the card, and replaces the * id with the new one. * * Returns zero if successful, or a negative error code on failure. */int snd_ctl_rename_id(snd_card_t * card, snd_ctl_elem_id_t *src_id, snd_ctl_elem_id_t *dst_id){	snd_kcontrol_t *kctl;	down_write(&card->controls_rwsem);	kctl = snd_ctl_find_id(card, src_id);	if (kctl == NULL) {		up_write(&card->controls_rwsem);

⌨️ 快捷键说明

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