Commit 7e4eeec8 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] Make buffer size of proc text interface variable



Make the read/write buffer size of proc text interface variable.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 2f4ca8e5
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -27,9 +27,9 @@
/* buffer for information */
struct snd_info_buffer {
	char *buffer;		/* pointer to begin of buffer */
	char *curr;		/* current position in buffer */
	unsigned long size;	/* current size */
	unsigned long len;	/* total length of buffer */
	unsigned int curr;	/* current position in buffer */
	unsigned int size;	/* current size */
	unsigned int len;	/* total length of buffer */
	int stop;		/* stop flag */
	int error;		/* error code */
};
+79 −70
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@

#include <sound/driver.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
@@ -82,6 +81,24 @@ static int snd_info_version_init(void);
static int snd_info_version_done(void);


/* 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
@@ -95,17 +112,25 @@ int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...)
{
	va_list args;
	int len, res;
	int err = 0;

	if (buffer->stop || buffer->error)
		return 0;
	len = buffer->len - buffer->size;
	va_start(args, fmt);
	res = vsnprintf(buffer->curr, len, fmt, args);
	va_end(args);
	if (res >= len) {
		buffer->stop = 1;
		return 0;
	for (;;) {
		res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args);
		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;
@@ -225,7 +250,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
	struct snd_info_private_data *data;
	struct snd_info_entry *entry;
	struct snd_info_buffer *buf;
	size_t size = 0;
	ssize_t size = 0;
	loff_t pos;

	data = file->private_data;
@@ -241,14 +266,20 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
		buf = data->wbuffer;
		if (buf == NULL)
			return -EIO;
		if (pos >= buf->len)
		mutex_unlock(&entry->access);
		if (pos + count >= buf->len) {
			if (resize_info_buffer(buf, pos + count)) {
				mutex_unlock(&entry->access);
				return -ENOMEM;
		size = buf->len - pos;
		size = min(count, size);
		if (copy_from_user(buf->buffer + pos, buffer, size))
			}
		}
		if (copy_from_user(buf->buffer + pos, buffer, count)) {
			mutex_unlock(&entry->access);
			return -EFAULT;
		if ((long)buf->size < pos + size)
			buf->size = pos + size;
		}
		buf->size = pos + count;
		mutex_unlock(&entry->access);
		size = count;
		break;
	case SNDRV_INFO_CONTENT_DATA:
		if (entry->c.ops->write)
@@ -283,18 +314,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
	}
	mode = file->f_flags & O_ACCMODE;
	if (mode == O_RDONLY || mode == O_RDWR) {
		if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
		     !entry->c.text.read_size) ||
		    (entry->content == SNDRV_INFO_CONTENT_DATA &&
		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_TEXT &&
		     !entry->c.text.write_size) ||
		    (entry->content == SNDRV_INFO_CONTENT_DATA &&
		if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
		     entry->c.ops->write == NULL)) {
		    	err = -ENODEV;
		    	goto __error;
@@ -310,49 +337,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
	case SNDRV_INFO_CONTENT_TEXT:
		if (mode == O_RDONLY || mode == O_RDWR) {
			buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
			if (buffer == NULL) {
				kfree(data);
				err = -ENOMEM;
				goto __error;
			}
			buffer->len = (entry->c.text.read_size +
				      (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
			buffer->buffer = vmalloc(buffer->len);
			if (buffer->buffer == NULL) {
				kfree(buffer);
				kfree(data);
				err = -ENOMEM;
				goto __error;
			}
			buffer->curr = buffer->buffer;
			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) {
				if (mode == O_RDWR) {
					vfree(data->rbuffer->buffer);
					kfree(data->rbuffer);
				}
				kfree(data);
				err = -ENOMEM;
				goto __error;
			}
			buffer->len = (entry->c.text.write_size +
				      (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
			buffer->buffer = vmalloc(buffer->len);
			if (buffer->buffer == NULL) {
				if (mode == O_RDWR) {
					vfree(data->rbuffer->buffer);
					kfree(data->rbuffer);
				}
				kfree(buffer);
				kfree(data);
				err = -ENOMEM;
				goto __error;
			}
			buffer->curr = buffer->buffer;
			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 */
@@ -377,6 +378,17 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
	}
	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:
@@ -395,11 +407,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
	entry = data->entry;
	switch (entry->content) {
	case SNDRV_INFO_CONTENT_TEXT:
		if (mode == O_RDONLY || mode == O_RDWR) {
			vfree(data->rbuffer->buffer);
		if (data->rbuffer) {
			kfree(data->rbuffer->buffer);
			kfree(data->rbuffer);
		}
		if (mode == O_WRONLY || mode == O_RDWR) {
		if (data->wbuffer) {
			if (entry->c.text.write) {
				entry->c.text.write(entry, data->wbuffer);
				if (data->wbuffer->error) {
@@ -408,7 +420,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
						data->wbuffer->error);
				}
			}
			vfree(data->wbuffer->buffer);
			kfree(data->wbuffer->buffer);
			kfree(data->wbuffer);
		}
		break;
@@ -668,25 +680,23 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
	if (len <= 0 || buffer->stop || buffer->error)
		return 1;
	while (--len > 0) {
		c = *buffer->curr++;
		c = buffer->buffer[buffer->curr++];
		if (c == '\n') {
			if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
			if (buffer->curr >= buffer->size)
				buffer->stop = 1;
			}
			break;
		}
		*line++ = c;
		if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
		if (buffer->curr >= buffer->size) {
			buffer->stop = 1;
			break;
		}
	}
	while (c != '\n' && !buffer->stop) {
		c = *buffer->curr++;
		if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
		c = buffer->buffer[buffer->curr++];
		if (buffer->curr >= buffer->size)
			buffer->stop = 1;
	}
	}
	*line = '\0';
	return 0;
}
@@ -978,7 +988,6 @@ static int __init snd_info_version_init(void)
	entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
	if (entry == NULL)
		return -ENOMEM;
	entry->c.text.read_size = 256;
	entry->c.text.read = snd_info_version_read;
	if (snd_info_register(entry) < 0) {
		snd_info_free_entry(entry);