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

📄 info.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Information interface for ALSA driver *  Copyright (c) by Jaroslav Kysela <perex@perex.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/init.h>#include <linux/time.h>#include <linux/smp_lock.h>#include <linux/string.h>#include <sound/core.h>#include <sound/minors.h>#include <sound/info.h>#include <sound/version.h>#include <linux/proc_fs.h>#include <linux/mutex.h>#include <stdarg.h>/* * */#ifdef CONFIG_PROC_FSint snd_info_check_reserved_words(const char *str){	static char *reserved[] =	{		"version",		"meminfo",		"memdebug",		"detect",		"devices",		"oss",		"cards",		"timers",		"synth",		"pcm",		"seq",		NULL	};	char **xstr = reserved;	while (*xstr) {		if (!strcmp(*xstr, str))			return 0;		xstr++;	}	if (!strncmp(str, "card", 4))		return 0;	return 1;}static DEFINE_MUTEX(info_mutex);struct snd_info_private_data {	struct snd_info_buffer *rbuffer;	struct snd_info_buffer *wbuffer;	struct snd_info_entry *entry;	void *file_private_data;};static int snd_info_version_init(void);static int snd_info_version_done(void);static void snd_info_disconnect(struct snd_info_entry *entry);/* resize the proc r/w buffer */static int resize_info_buffer(struct snd_info_buffer *buffer,			      unsigned int nsize){	char *nbuf;	nsize = PAGE_ALIGN(nsize);	nbuf = kmalloc(nsize, GFP_KERNEL);	if (! nbuf)		return -ENOMEM;	memcpy(nbuf, buffer->buffer, buffer->len);	kfree(buffer->buffer);	buffer->buffer = nbuf;	buffer->len = nsize;	return 0;}/** * snd_iprintf - printf on the procfs buffer * @buffer: the procfs buffer * @fmt: the printf format * * Outputs the string on the procfs buffer just like printf(). * * Returns the size of output string. */int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...){	va_list args;	int len, res;	int err = 0;	might_sleep();	if (buffer->stop || buffer->error)		return 0;	len = buffer->len - buffer->size;	va_start(args, fmt);	for (;;) {		va_list ap;		va_copy(ap, args);		res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, ap);		va_end(ap);		if (res < len)			break;		err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);		if (err < 0)			break;		len = buffer->len - buffer->size;	}	va_end(args);	if (err < 0)		return err;	buffer->curr += res;	buffer->size += res;	return res;}EXPORT_SYMBOL(snd_iprintf);/* */static struct proc_dir_entry *snd_proc_root;struct snd_info_entry *snd_seq_root;EXPORT_SYMBOL(snd_seq_root);#ifdef CONFIG_SND_OSSEMULstruct snd_info_entry *snd_oss_root;#endifstatic inline void snd_info_entry_prepare(struct proc_dir_entry *de){	de->owner = THIS_MODULE;}static void snd_remove_proc_entry(struct proc_dir_entry *parent,				  struct proc_dir_entry *de){	if (de)		remove_proc_entry(de->name, parent);}static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig){	struct snd_info_private_data *data;	struct snd_info_entry *entry;	loff_t ret;	data = file->private_data;	entry = data->entry;	lock_kernel();	switch (entry->content) {	case SNDRV_INFO_CONTENT_TEXT:		switch (orig) {		case SEEK_SET:			file->f_pos = offset;			ret = file->f_pos;			goto out;		case SEEK_CUR:			file->f_pos += offset;			ret = file->f_pos;			goto out;		case SEEK_END:		default:			ret = -EINVAL;			goto out;		}		break;	case SNDRV_INFO_CONTENT_DATA:		if (entry->c.ops->llseek) {			ret = entry->c.ops->llseek(entry,						    data->file_private_data,						    file, offset, orig);			goto out;		}		break;	}	ret = -ENXIO;out:	unlock_kernel();	return ret;}static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,				   size_t count, loff_t * offset){	struct snd_info_private_data *data;	struct snd_info_entry *entry;	struct snd_info_buffer *buf;	size_t size = 0;	loff_t pos;	data = file->private_data;	snd_assert(data != NULL, return -ENXIO);	pos = *offset;	if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)		return -EIO;	if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)		return -EIO;	entry = data->entry;	switch (entry->content) {	case SNDRV_INFO_CONTENT_TEXT:		buf = data->rbuffer;		if (buf == NULL)			return -EIO;		if (pos >= buf->size)			return 0;		size = buf->size - pos;		size = min(count, size);		if (copy_to_user(buffer, buf->buffer + pos, size))			return -EFAULT;		break;	case SNDRV_INFO_CONTENT_DATA:		if (entry->c.ops->read)			size = entry->c.ops->read(entry,						  data->file_private_data,						  file, buffer, count, pos);		break;	}	if ((ssize_t) size > 0)		*offset = pos + size;	return size;}static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,				    size_t count, loff_t * offset){	struct snd_info_private_data *data;	struct snd_info_entry *entry;	struct snd_info_buffer *buf;	ssize_t size = 0;	loff_t pos;	data = file->private_data;	snd_assert(data != NULL, return -ENXIO);	entry = data->entry;	pos = *offset;	if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)		return -EIO;	if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)		return -EIO;	switch (entry->content) {	case SNDRV_INFO_CONTENT_TEXT:		buf = data->wbuffer;		if (buf == NULL)			return -EIO;		mutex_lock(&entry->access);		if (pos + count >= buf->len) {			if (resize_info_buffer(buf, pos + count)) {				mutex_unlock(&entry->access);				return -ENOMEM;			}		}		if (copy_from_user(buf->buffer + pos, buffer, count)) {			mutex_unlock(&entry->access);			return -EFAULT;		}		buf->size = pos + count;		mutex_unlock(&entry->access);		size = count;		break;	case SNDRV_INFO_CONTENT_DATA:		if (entry->c.ops->write)			size = entry->c.ops->write(entry,						   data->file_private_data,						   file, buffer, count, pos);		break;	}	if ((ssize_t) size > 0)		*offset = pos + size;	return size;}static int snd_info_entry_open(struct inode *inode, struct file *file){	struct snd_info_entry *entry;	struct snd_info_private_data *data;	struct snd_info_buffer *buffer;	struct proc_dir_entry *p;	int mode, err;	mutex_lock(&info_mutex);	p = PDE(inode);	entry = p == NULL ? NULL : (struct snd_info_entry *)p->data;	if (entry == NULL || ! entry->p) {		mutex_unlock(&info_mutex);		return -ENODEV;	}	if (!try_module_get(entry->module)) {		err = -EFAULT;		goto __error1;	}	mode = file->f_flags & O_ACCMODE;	if (mode == O_RDONLY || mode == O_RDWR) {		if ((entry->content == SNDRV_INFO_CONTENT_DATA &&		     entry->c.ops->read == NULL)) {		    	err = -ENODEV;		    	goto __error;		}	}	if (mode == O_WRONLY || mode == O_RDWR) {		if ((entry->content == SNDRV_INFO_CONTENT_DATA &&		     entry->c.ops->write == NULL)) {		    	err = -ENODEV;		    	goto __error;		}	}	data = kzalloc(sizeof(*data), GFP_KERNEL);	if (data == NULL) {		err = -ENOMEM;		goto __error;	}	data->entry = entry;	switch (entry->content) {	case SNDRV_INFO_CONTENT_TEXT:		if (mode == O_RDONLY || mode == O_RDWR) {			buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);			if (buffer == NULL)				goto __nomem;			data->rbuffer = buffer;			buffer->len = PAGE_SIZE;			buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);			if (buffer->buffer == NULL)				goto __nomem;		}		if (mode == O_WRONLY || mode == O_RDWR) {			buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);			if (buffer == NULL)				goto __nomem;			data->wbuffer = buffer;			buffer->len = PAGE_SIZE;			buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);			if (buffer->buffer == NULL)				goto __nomem;		}		break;	case SNDRV_INFO_CONTENT_DATA:	/* data */		if (entry->c.ops->open) {			if ((err = entry->c.ops->open(entry, mode,						      &data->file_private_data)) < 0) {				kfree(data);				goto __error;			}		}		break;	}	file->private_data = data;	mutex_unlock(&info_mutex);	if (entry->content == SNDRV_INFO_CONTENT_TEXT &&	    (mode == O_RDONLY || mode == O_RDWR)) {		if (entry->c.text.read) {			mutex_lock(&entry->access);			entry->c.text.read(entry, data->rbuffer);			mutex_unlock(&entry->access);		}	}	return 0; __nomem:	if (data->rbuffer) {		kfree(data->rbuffer->buffer);		kfree(data->rbuffer);	}	if (data->wbuffer) {		kfree(data->wbuffer->buffer);		kfree(data->wbuffer);	}	kfree(data);	err = -ENOMEM;      __error:	module_put(entry->module);      __error1:	mutex_unlock(&info_mutex);	return err;}static int snd_info_entry_release(struct inode *inode, struct file *file){	struct snd_info_entry *entry;	struct snd_info_private_data *data;	int mode;	mode = file->f_flags & O_ACCMODE;	data = file->private_data;	entry = data->entry;	switch (entry->content) {	case SNDRV_INFO_CONTENT_TEXT:		if (data->rbuffer) {			kfree(data->rbuffer->buffer);			kfree(data->rbuffer);		}		if (data->wbuffer) {			if (entry->c.text.write) {				entry->c.text.write(entry, data->wbuffer);				if (data->wbuffer->error) {					snd_printk(KERN_WARNING "data write error to %s (%i)\n",						entry->name,						data->wbuffer->error);				}			}			kfree(data->wbuffer->buffer);			kfree(data->wbuffer);		}		break;	case SNDRV_INFO_CONTENT_DATA:		if (entry->c.ops->release)			entry->c.ops->release(entry, mode,					      data->file_private_data);		break;	}	module_put(entry->module);	kfree(data);	return 0;}static unsigned int snd_info_entry_poll(struct file *file, poll_table * wait){	struct snd_info_private_data *data;	struct snd_info_entry *entry;	unsigned int mask;	data = file->private_data;	if (data == NULL)		return 0;	entry = data->entry;	mask = 0;	switch (entry->content) {	case SNDRV_INFO_CONTENT_DATA:		if (entry->c.ops->poll)			return entry->c.ops->poll(entry,						  data->file_private_data,						  file, wait);		if (entry->c.ops->read)			mask |= POLLIN | POLLRDNORM;		if (entry->c.ops->write)			mask |= POLLOUT | POLLWRNORM;		break;	}	return mask;}static long snd_info_entry_ioctl(struct file *file, unsigned int cmd,				unsigned long arg){	struct snd_info_private_data *data;	struct snd_info_entry *entry;	data = file->private_data;	if (data == NULL)		return 0;	entry = data->entry;	switch (entry->content) {	case SNDRV_INFO_CONTENT_DATA:		if (entry->c.ops->ioctl)			return entry->c.ops->ioctl(entry,						   data->file_private_data,						   file, cmd, arg);		break;	}	return -ENOTTY;}static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma){	struct inode *inode = file->f_path.dentry->d_inode;	struct snd_info_private_data *data;	struct snd_info_entry *entry;	data = file->private_data;	if (data == NULL)		return 0;	entry = data->entry;	switch (entry->content) {	case SNDRV_INFO_CONTENT_DATA:		if (entry->c.ops->mmap)			return entry->c.ops->mmap(entry,						  data->file_private_data,						  inode, file, vma);		break;

⌨️ 快捷键说明

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