diff options
| author | Frank Mori Hess <fmhess@users.sourceforge.net> | 2009-04-14 11:21:41 -0400 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-19 11:00:30 -0700 | 
| commit | 883db3d9bb4d50f05cbb8b5197f6aef10c1231a9 (patch) | |
| tree | 8c696828a31546c7ce77ae15a493d93d0a6628b8 | |
| parent | 0d6e5dad12c5a2860e3d13b4d7a4702f90386003 (diff) | |
Staging: comedi: Added sysfs attribute files for setting and querying subdevice buffer sizes.
Signed-off-by: Frank Mori Hess <fmhess@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/staging/comedi/comedi_fops.c | 418 | 
1 files changed, 379 insertions, 39 deletions
| diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 19dce2ebfc1..bb4a2897fea 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -44,6 +44,7 @@  #include <linux/fs.h>  #include "comedidev.h"  #include <linux/cdev.h> +#include <linux/stat.h>  #include <linux/io.h>  #include <linux/uaccess.h> @@ -92,6 +93,15 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);  static int comedi_fasync(int fd, struct file *file, int on);  static int is_device_busy(struct comedi_device *dev); +static int resize_async_buffer(struct comedi_device *dev, +			       struct comedi_subdevice *s, +			       struct comedi_async *async, unsigned new_size); + +/* declarations for sysfs attribute files */ +static struct device_attribute dev_attr_max_read_buffer_kb; +static struct device_attribute dev_attr_read_buffer_kb; +static struct device_attribute dev_attr_max_write_buffer_kb; +static struct device_attribute dev_attr_write_buffer_kb;  #ifdef HAVE_UNLOCKED_IOCTL  static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, @@ -277,7 +287,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg)  	struct comedi_bufconfig bc;  	struct comedi_async *async;  	struct comedi_subdevice *s; -	int ret = 0; +	int retval = 0;  	if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))  		return -EFAULT; @@ -303,37 +313,9 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg)  	}  	if (bc.size) { -		if (bc.size > async->max_bufsize) -			return -EPERM; - -		if (s->busy) { -			DPRINTK("subdevice is busy, cannot resize buffer\n"); -			return -EBUSY; -		} -		if (async->mmap_count) { -			DPRINTK("subdevice is mmapped, cannot resize buffer\n"); -			return -EBUSY; -		} - -		if (!async->prealloc_buf) -			return -EINVAL; - -		/* make sure buffer is an integral number of pages -		 * (we round up) */ -		bc.size = (bc.size + PAGE_SIZE - 1) & PAGE_MASK; - -		ret = comedi_buf_alloc(dev, s, bc.size); -		if (ret < 0) -			return ret; - -		if (s->buf_change) { -			ret = s->buf_change(dev, s, bc.size); -			if (ret < 0) -				return ret; -		} - -		DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", -			dev->minor, bc.subdevice, async->prealloc_bufsz); +		retval = resize_async_buffer(dev, s, async, bc.size); +		if (retval < 0) +			return retval;  	}  	bc.size = async->prealloc_bufsz; @@ -2132,6 +2114,7 @@ int comedi_alloc_board_minor(struct device *hardware_device)  	struct comedi_device_file_info *info;  	struct device *csdev;  	unsigned i; +	int retval;  	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);  	if (info == NULL) @@ -2154,8 +2137,7 @@ int comedi_alloc_board_minor(struct device *hardware_device)  		comedi_device_cleanup(info->device);  		kfree(info->device);  		kfree(info); -		rt_printk -		    ("comedi: error: ran out of minor numbers for board device files.\n"); +		printk(KERN_ERR "comedi: error: ran out of minor numbers for board device files.\n");  		return -EBUSY;  	}  	info->device->minor = i; @@ -2164,7 +2146,35 @@ int comedi_alloc_board_minor(struct device *hardware_device)  				     hardware_device, "comedi%i", i);  	if (!IS_ERR(csdev))  		info->device->class_dev = csdev; - +	dev_set_drvdata(csdev, info); +	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); +	if (retval) { +		printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", +			dev_attr_max_read_buffer_kb.attr.name); +		comedi_free_board_minor(i); +		return retval; +	} +	retval = device_create_file(csdev, &dev_attr_read_buffer_kb); +	if (retval) { +		printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", +			dev_attr_read_buffer_kb.attr.name); +		comedi_free_board_minor(i); +		return retval; +	} +	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); +	if (retval) { +		printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", +			dev_attr_max_write_buffer_kb.attr.name); +		comedi_free_board_minor(i); +		return retval; +	} +	retval = device_create_file(csdev, &dev_attr_write_buffer_kb); +	if (retval) { +		printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", +			dev_attr_write_buffer_kb.attr.name); +		comedi_free_board_minor(i); +		return retval; +	}  	return i;  } @@ -2193,12 +2203,14 @@ void comedi_free_board_minor(unsigned minor)  	}  } -int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s) +int comedi_alloc_subdevice_minor(struct comedi_device *dev, +				 struct comedi_subdevice *s)  {  	unsigned long flags;  	struct comedi_device_file_info *info;  	struct device *csdev;  	unsigned i; +	int retval;  	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);  	if (info == NULL) @@ -2216,8 +2228,7 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdev  	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);  	if (i == COMEDI_NUM_MINORS) {  		kfree(info); -		rt_printk -		    ("comedi: error: ran out of minor numbers for board device files.\n"); +		printk(KERN_ERR "comedi: error: ran out of minor numbers for board device files.\n");  		return -EBUSY;  	}  	s->minor = i; @@ -2227,7 +2238,35 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdev  				     (int)(s - dev->subdevices));  	if (!IS_ERR(csdev))  		s->class_dev = csdev; - +	dev_set_drvdata(csdev, info); +	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); +	if (retval) { +		printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", +			dev_attr_max_read_buffer_kb.attr.name); +		comedi_free_subdevice_minor(s); +		return retval; +	} +	retval = device_create_file(csdev, &dev_attr_read_buffer_kb); +	if (retval) { +		printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", +			dev_attr_read_buffer_kb.attr.name); +		comedi_free_subdevice_minor(s); +		return retval; +	} +	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); +	if (retval) { +		printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", +			dev_attr_max_write_buffer_kb.attr.name); +		comedi_free_subdevice_minor(s); +		return retval; +	} +	retval = device_create_file(csdev, &dev_attr_write_buffer_kb); +	if (retval) { +		printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", +			dev_attr_write_buffer_kb.attr.name); +		comedi_free_subdevice_minor(s); +		return retval; +	}  	return i;  } @@ -2267,3 +2306,304 @@ struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)  	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);  	return info;  } + +static int resize_async_buffer(struct comedi_device *dev, +			       struct comedi_subdevice *s, +			       struct comedi_async *async, unsigned new_size) +{ +	int retval; + +	if (new_size > async->max_bufsize) +		return -EPERM; + +	if (s->busy) { +		DPRINTK("subdevice is busy, cannot resize buffer\n"); +		return -EBUSY; +	} +	if (async->mmap_count) { +		DPRINTK("subdevice is mmapped, cannot resize buffer\n"); +		return -EBUSY; +	} + +	if (!async->prealloc_buf) +		return -EINVAL; + +	/* make sure buffer is an integral number of pages +		* (we round up) */ +	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; + +	retval = comedi_buf_alloc(dev, s, new_size); +	if (retval < 0) +		return retval; + +	if (s->buf_change) { +		retval = s->buf_change(dev, s, new_size); +		if (retval < 0) +			return retval; +	} + +	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", +		dev->minor, s - dev->subdevices, async->prealloc_bufsz); +	return 0; +} + +/* sysfs attribute files */ + +static const unsigned bytes_per_kibi = 1024; + +static ssize_t show_max_read_buffer_kb(struct device *dev, +				       struct device_attribute *attr, char *buf) +{ +	ssize_t retval; +	struct comedi_device_file_info *info = dev_get_drvdata(dev); +	unsigned max_buffer_size_kb = 0; +	struct comedi_subdevice *const read_subdevice = +					comedi_get_read_subdevice(info); + +	mutex_lock(&info->device->mutex); +	if (read_subdevice && +	    (read_subdevice->subdev_flags & SDF_CMD_READ) && +	    read_subdevice->async) { +		max_buffer_size_kb = read_subdevice->async->max_bufsize / +					bytes_per_kibi; +	} +	retval =  snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); +	mutex_unlock(&info->device->mutex); + +	return retval; +} + +static ssize_t store_max_read_buffer_kb(struct device *dev, +					struct device_attribute *attr, +					const char *buf, size_t count) +{ +	struct comedi_device_file_info *info = dev_get_drvdata(dev); +	unsigned long new_max_size_kb; +	uint64_t new_max_size; +	struct comedi_subdevice *const read_subdevice = +					comedi_get_read_subdevice(info); + +	if (strict_strtoul(buf, 10, &new_max_size_kb)) +		return -EINVAL; +	if (new_max_size_kb != (uint32_t)new_max_size_kb) +		return -EINVAL; +	new_max_size = ((uint64_t)new_max_size_kb) * bytes_per_kibi; +	if (new_max_size != (uint32_t)new_max_size) +		return -EINVAL; + +	mutex_lock(&info->device->mutex); +	if (read_subdevice == NULL || +	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || +	    read_subdevice->async == NULL) { +		mutex_unlock(&info->device->mutex); +		return -EINVAL; +	} +	read_subdevice->async->max_bufsize = new_max_size; +	mutex_unlock(&info->device->mutex); + +	return count; +} + +static struct device_attribute dev_attr_max_read_buffer_kb = { +	.attr = { +			.name = "max_read_buffer_kb", +			.mode = S_IRUGO | S_IWUSR +		}, +	.show = &show_max_read_buffer_kb, +	.store = &store_max_read_buffer_kb +}; + +static ssize_t show_read_buffer_kb(struct device *dev, +				   struct device_attribute *attr, char *buf) +{ +	ssize_t retval; +	struct comedi_device_file_info *info = dev_get_drvdata(dev); +	unsigned buffer_size_kb = 0; +	struct comedi_subdevice *const read_subdevice = +					comedi_get_read_subdevice(info); + +	mutex_lock(&info->device->mutex); +	if (read_subdevice && +		(read_subdevice->subdev_flags & SDF_CMD_READ) && +		read_subdevice->async) { +		buffer_size_kb = read_subdevice->async->prealloc_bufsz / +					bytes_per_kibi; +	} +	retval =  snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); +	mutex_unlock(&info->device->mutex); + +	return retval; +} + +static ssize_t store_read_buffer_kb(struct device *dev, +				    struct device_attribute *attr, +				    const char *buf, size_t count) +{ +	struct comedi_device_file_info *info = dev_get_drvdata(dev); +	unsigned long new_size_kb; +	uint64_t new_size; +	int retval; +	struct comedi_subdevice *const read_subdevice = +					comedi_get_read_subdevice(info); + +	if (strict_strtoul(buf, 10, &new_size_kb)) +		return -EINVAL; +	if (new_size_kb != (uint32_t)new_size_kb) +		return -EINVAL; +	new_size = ((uint64_t)new_size_kb) * bytes_per_kibi; +	if (new_size != (uint32_t)new_size) +		return -EINVAL; + +	mutex_lock(&info->device->mutex); +	if (read_subdevice == NULL || +	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || +	    read_subdevice->async == NULL) { +		mutex_unlock(&info->device->mutex); +		return -EINVAL; +	} +	retval = resize_async_buffer(info->device, read_subdevice, +				     read_subdevice->async, new_size); +	mutex_unlock(&info->device->mutex); + +	if (retval < 0) +		return retval; +	return count; +} + +static struct device_attribute dev_attr_read_buffer_kb = { +	.attr = { +			.name = "read_buffer_kb", +			.mode = S_IRUGO | S_IWUSR | S_IWGRP +		}, +	.show = &show_read_buffer_kb, +	.store = &store_read_buffer_kb +}; + +static ssize_t show_max_write_buffer_kb(struct device *dev, +					struct device_attribute *attr, +					char *buf) +{ +	ssize_t retval; +	struct comedi_device_file_info *info = dev_get_drvdata(dev); +	unsigned max_buffer_size_kb = 0; +	struct comedi_subdevice *const write_subdevice = +					comedi_get_write_subdevice(info); + +	mutex_lock(&info->device->mutex); +	if (write_subdevice && +	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) && +	    write_subdevice->async) { +		max_buffer_size_kb = write_subdevice->async->max_bufsize / +					bytes_per_kibi; +	} +	retval =  snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); +	mutex_unlock(&info->device->mutex); + +	return retval; +} + +static ssize_t store_max_write_buffer_kb(struct device *dev, +					 struct device_attribute *attr, +					 const char *buf, size_t count) +{ +	struct comedi_device_file_info *info = dev_get_drvdata(dev); +	unsigned long new_max_size_kb; +	uint64_t new_max_size; +	struct comedi_subdevice *const write_subdevice = +					comedi_get_write_subdevice(info); + +	if (strict_strtoul(buf, 10, &new_max_size_kb)) +		return -EINVAL; +	if (new_max_size_kb != (uint32_t)new_max_size_kb) +		return -EINVAL; +	new_max_size = ((uint64_t)new_max_size_kb) * bytes_per_kibi; +	if (new_max_size != (uint32_t)new_max_size) +		return -EINVAL; + +	mutex_lock(&info->device->mutex); +	if (write_subdevice == NULL || +	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || +	    write_subdevice->async == NULL) { +		mutex_unlock(&info->device->mutex); +		return -EINVAL; +	} +	write_subdevice->async->max_bufsize = new_max_size; +	mutex_unlock(&info->device->mutex); + +	return count; +} + +static struct device_attribute dev_attr_max_write_buffer_kb = { +	.attr = { +			.name = "max_write_buffer_kb", +			.mode = S_IRUGO | S_IWUSR +		}, +	.show = &show_max_write_buffer_kb, +	.store = &store_max_write_buffer_kb +}; + +static ssize_t show_write_buffer_kb(struct device *dev, +				    struct device_attribute *attr, char *buf) +{ +	ssize_t retval; +	struct comedi_device_file_info *info = dev_get_drvdata(dev); +	unsigned buffer_size_kb = 0; +	struct comedi_subdevice *const write_subdevice = +					comedi_get_write_subdevice(info); + +	mutex_lock(&info->device->mutex); +	if (write_subdevice && +	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) && +	    write_subdevice->async) { +		buffer_size_kb = write_subdevice->async->prealloc_bufsz / +					bytes_per_kibi; +	} +	retval =  snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); +	mutex_unlock(&info->device->mutex); + +	return retval; +} + +static ssize_t store_write_buffer_kb(struct device *dev, +				     struct device_attribute *attr, +				     const char *buf, size_t count) +{ +	struct comedi_device_file_info *info = dev_get_drvdata(dev); +	unsigned long new_size_kb; +	uint64_t new_size; +	int retval; +	struct comedi_subdevice *const write_subdevice = +					comedi_get_write_subdevice(info); + +	if (strict_strtoul(buf, 10, &new_size_kb)) +		return -EINVAL; +	if (new_size_kb != (uint32_t)new_size_kb) +		return -EINVAL; +	new_size = ((uint64_t)new_size_kb) * bytes_per_kibi; +	if (new_size != (uint32_t)new_size) +		return -EINVAL; + +	mutex_lock(&info->device->mutex); +	if (write_subdevice == NULL || +	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || +	    write_subdevice->async == NULL) { +		mutex_unlock(&info->device->mutex); +		return -EINVAL; +	} +	retval = resize_async_buffer(info->device, write_subdevice, +		write_subdevice->async, new_size); +	mutex_unlock(&info->device->mutex); + +	if (retval < 0) +		return retval; +	return count; +} + +static struct device_attribute dev_attr_write_buffer_kb = { +	.attr = { +			.name = "write_buffer_kb", +			.mode = S_IRUGO | S_IWUSR | S_IWGRP +		}, +	.show = &show_write_buffer_kb, +	.store = &store_write_buffer_kb +}; | 
