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

📄 control.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
		return -ENOENT;	}	kctl->id = *dst_id;	kctl->id.numid = card->last_numid + 1;	card->last_numid += kctl->count;	up_write(&card->controls_rwsem);	return 0;}/** * snd_ctl_find_numid - find the control instance with the given number-id * @card: the card instance * @numid: the number-id to search * * Finds the control instance with the given number-id from the card. * * Returns the pointer of the instance if found, or NULL if not. * * The caller must down card->controls_rwsem before calling this function * (if the race condition can happen). */snd_kcontrol_t *snd_ctl_find_numid(snd_card_t * card, unsigned int numid){	struct list_head *list;	snd_kcontrol_t *kctl;	snd_runtime_check(card != NULL && numid != 0, return NULL);	list_for_each(list, &card->controls) {		kctl = snd_kcontrol(list);		if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)			return kctl;	}	return NULL;}/** * snd_ctl_find_id - find the control instance with the given id * @card: the card instance * @id: the id to search * * Finds the control instance with the given id from the card. * * Returns the pointer of the instance if found, or NULL if not. * * The caller must down card->controls_rwsem before calling this function * (if the race condition can happen). */snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id){	struct list_head *list;	snd_kcontrol_t *kctl;	snd_runtime_check(card != NULL && id != NULL, return NULL);	if (id->numid != 0)		return snd_ctl_find_numid(card, id->numid);	list_for_each(list, &card->controls) {		kctl = snd_kcontrol(list);		if (kctl->id.iface != id->iface)			continue;		if (kctl->id.device != id->device)			continue;		if (kctl->id.subdevice != id->subdevice)			continue;		if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)))			continue;		if (kctl->id.index > id->index)			continue;		if (kctl->id.index + kctl->count <= id->index)			continue;		return kctl;	}	return NULL;}static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,			     unsigned int cmd, void __user *arg){	snd_ctl_card_info_t info;	memset(&info, 0, sizeof(info));	down_read(&snd_ioctl_rwsem);	info.card = card->number;	strlcpy(info.id, card->id, sizeof(info.id));	strlcpy(info.driver, card->driver, sizeof(info.driver));	strlcpy(info.name, card->shortname, sizeof(info.name));	strlcpy(info.longname, card->longname, sizeof(info.longname));	strlcpy(info.mixername, card->mixername, sizeof(info.mixername));	strlcpy(info.components, card->components, sizeof(info.components));	up_read(&snd_ioctl_rwsem);	if (copy_to_user(arg, &info, sizeof(snd_ctl_card_info_t)))		return -EFAULT;	return 0;}static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list){	struct list_head *plist;	snd_ctl_elem_list_t list;	snd_kcontrol_t *kctl;	snd_ctl_elem_id_t *dst, *id;	unsigned int offset, space, first, jidx;		if (copy_from_user(&list, _list, sizeof(list)))		return -EFAULT;	offset = list.offset;	space = list.space;	first = 0;	/* try limit maximum space */	if (space > 16384)		return -ENOMEM;	if (space > 0) {		/* allocate temporary buffer for atomic operation */		dst = vmalloc(space * sizeof(snd_ctl_elem_id_t));		if (dst == NULL)			return -ENOMEM;		down_read(&card->controls_rwsem);		list.count = card->controls_count;		plist = card->controls.next;		while (plist != &card->controls) {			if (offset == 0)				break;			kctl = snd_kcontrol(plist);			if (offset < kctl->count)				break;			offset -= kctl->count;			plist = plist->next;		}		list.used = 0;		id = dst;		while (space > 0 && plist != &card->controls) {			kctl = snd_kcontrol(plist);			for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {				snd_ctl_build_ioff(id, kctl, jidx);				id++;				space--;				list.used++;			}			plist = plist->next;			offset = 0;		}		up_read(&card->controls_rwsem);		if (list.used > 0 && copy_to_user(list.pids, dst, list.used * sizeof(snd_ctl_elem_id_t))) {			vfree(dst);			return -EFAULT;		}		vfree(dst);	} else {		down_read(&card->controls_rwsem);		list.count = card->controls_count;		up_read(&card->controls_rwsem);	}	if (copy_to_user(_list, &list, sizeof(list)))		return -EFAULT;	return 0;}static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info){	snd_card_t *card = ctl->card;	snd_ctl_elem_info_t info;	snd_kcontrol_t *kctl;	snd_kcontrol_volatile_t *vd;	unsigned int index_offset;	int result;		if (copy_from_user(&info, _info, sizeof(info)))		return -EFAULT;	down_read(&card->controls_rwsem);	kctl = snd_ctl_find_id(card, &info.id);	if (kctl == NULL) {		up_read(&card->controls_rwsem);		return -ENOENT;	}#ifdef CONFIG_SND_DEBUG	info.access = 0;#endif	result = kctl->info(kctl, &info);	if (result >= 0) {		snd_assert(info.access == 0, );		index_offset = snd_ctl_get_ioff(kctl, &info.id);		vd = &kctl->vd[index_offset];		snd_ctl_build_ioff(&info.id, kctl, index_offset);		info.access = vd->access;		if (vd->owner) {			info.access |= SNDRV_CTL_ELEM_ACCESS_LOCK;			if (vd->owner == ctl)				info.access |= SNDRV_CTL_ELEM_ACCESS_OWNER;			info.owner = vd->owner_pid;		} else {			info.owner = -1;		}	}	up_read(&card->controls_rwsem);	if (result >= 0)		if (copy_to_user(_info, &info, sizeof(info)))			return -EFAULT;	return result;}static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t __user *_control){	snd_ctl_elem_value_t *control;	snd_kcontrol_t *kctl;	snd_kcontrol_volatile_t *vd;	unsigned int index_offset;	int result, indirect;		control = kmalloc(sizeof(*control), GFP_KERNEL);	if (control == NULL)		return -ENOMEM;		if (copy_from_user(control, _control, sizeof(*control)))		return -EFAULT;	down_read(&card->controls_rwsem);	kctl = snd_ctl_find_id(card, &control->id);	if (kctl == NULL) {		result = -ENOENT;	} else {		index_offset = snd_ctl_get_ioff(kctl, &control->id);		vd = &kctl->vd[index_offset];		indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;		if (control->indirect != indirect) {			result = -EACCES;		} else {			if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) {				snd_ctl_build_ioff(&control->id, kctl, index_offset);				result = kctl->get(kctl, control);			} else {				result = -EPERM;			}		}	}	up_read(&card->controls_rwsem);	if (result >= 0)		if (copy_to_user(_control, control, sizeof(*control)))			return -EFAULT;	kfree(control);	return result;}static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t __user *_control){	snd_card_t *card = file->card;	snd_ctl_elem_value_t *control;	snd_kcontrol_t *kctl;	snd_kcontrol_volatile_t *vd;	unsigned int index_offset;	int result, indirect;	control = kmalloc(sizeof(*control), GFP_KERNEL);	if (control == NULL)		return -ENOMEM;		if (copy_from_user(control, _control, sizeof(*control)))		return -EFAULT;	down_read(&card->controls_rwsem);	kctl = snd_ctl_find_id(card, &control->id);	if (kctl == NULL) {		result = -ENOENT;	} else {		index_offset = snd_ctl_get_ioff(kctl, &control->id);		vd = &kctl->vd[index_offset];		indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;		if (control->indirect != indirect) {			result = -EACCES;		} else {			if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||			    kctl->put == NULL ||			    (vd->owner != NULL && vd->owner != file)) {				result = -EPERM;			} else {				snd_ctl_build_ioff(&control->id, kctl, index_offset);				result = kctl->put(kctl, control);			}			if (result > 0) {				up_read(&card->controls_rwsem);				snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &control->id);				result = 0;				goto __unlocked;			}		}	}	up_read(&card->controls_rwsem);      __unlocked:	if (result >= 0)		if (copy_to_user(_control, control, sizeof(*control)))			return -EFAULT;	kfree(control);	return result;}static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id){	snd_card_t *card = file->card;	snd_ctl_elem_id_t id;	snd_kcontrol_t *kctl;	snd_kcontrol_volatile_t *vd;	int result;		if (copy_from_user(&id, _id, sizeof(id)))		return -EFAULT;	down_write(&card->controls_rwsem);	kctl = snd_ctl_find_id(card, &id);	if (kctl == NULL) {		result = -ENOENT;	} else {		vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];		if (vd->owner != NULL)			result = -EBUSY;		else {			vd->owner = file;			vd->owner_pid = current->pid;			result = 0;		}	}	up_write(&card->controls_rwsem);	return result;}static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id){	snd_card_t *card = file->card;	snd_ctl_elem_id_t id;	snd_kcontrol_t *kctl;	snd_kcontrol_volatile_t *vd;	int result;		if (copy_from_user(&id, _id, sizeof(id)))		return -EFAULT;	down_write(&card->controls_rwsem);	kctl = snd_ctl_find_id(card, &id);	if (kctl == NULL) {		result = -ENOENT;	} else {		vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];		if (vd->owner == NULL)			result = -EINVAL;		else if (vd->owner != file)			result = -EPERM;		else {			vd->owner = NULL;			vd->owner_pid = 0;			result = 0;		}	}	up_write(&card->controls_rwsem);	return result;}struct user_element {	enum sndrv_ctl_elem_type type;	/* element type */	unsigned int elem_count;	/* count of elements */	union {		struct {			unsigned int items;		} enumerated;	} u;	void *elem_data;		/* element data */	unsigned long elem_data_size;	/* size of element data in bytes */	void *priv_data;		/* private data (like strings for enumerated type) */	unsigned long priv_data_size;	/* size of private data in bytes */	unsigned short dimen_count;	/* count of dimensions */	unsigned short dimen[0];	/* array of dimensions */};static int snd_ctl_elem_user_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	struct user_element *ue = kcontrol->private_data;	uinfo->type = ue->type;	uinfo->count = ue->elem_count;	if (ue->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {		uinfo->value.enumerated.items = ue->u.enumerated.items;		if (uinfo->value.enumerated.item >= ue->u.enumerated.items)			uinfo->value.enumerated.item = 0;		strlcpy(uinfo->value.enumerated.name,			(char *)ue->priv_data + uinfo->value.enumerated.item * 64,			64);	}	return 0;}static int snd_ctl_elem_user_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	struct user_element *ue = kcontrol->private_data;	memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);	return 0;}static int snd_ctl_elem_user_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	int change;	struct user_element *ue = kcontrol->private_data;		change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size);	memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);	return !!change;}static void snd_ctl_elem_user_free(snd_kcontrol_t * kcontrol){	kfree(kcontrol->private_data);}static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace){	snd_card_t *card = file->card;	snd_ctl_elem_info_t info;	snd_kcontrol_t kctl, *_kctl;	unsigned int access;	long private_size, dimen_size, extra_size;	struct user_element *ue;	int idx, err;		if (copy_from_user(&info, _info, sizeof(info)))		return -EFAULT;	if (info.count > 1024)		return -EINVAL;	access = info.access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :		 (info.access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE|		 		 SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT));	if (access & (SNDRV_CTL_ELEM_ACCESS_DINDIRECT | SNDRV_CTL_ELEM_ACCESS_INDIRECT))		return -EINVAL;	info.id.numid = 0;	memset(&kctl, 0, sizeof(kctl));	down_write(&card->controls_rwsem);	if (!!((_kctl = snd_ctl_find_id(card, &info.id)) != NULL) ^ replace) {		up_write(&card->controls_rwsem);		return !replace ? -EBUSY : -ENOENT;	}	if (replace) {		err = snd_ctl_remove(card, _kctl);		if (err < 0) {			up_write(&card->controls_rwsem);			return err;		}	}	up_write(&card->controls_rwsem);	memcpy(&kctl.id, &info.id, sizeof(info.id));

⌨️ 快捷键说明

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