Commit a5011a26 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: refactor sysfs files in comedi_fops.c

Refactor the sysfs attributes and functions to remove
the need for the forward declarations and use the
DEVICE_ATTR macro to define them.

Instead of individually creating sysfs device attribute
files, wrap them in an attribute_group and use the
sysfs_create_group function to create them.
Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Cc: Mori Hess <fmhess@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 54fe68a8
...@@ -129,15 +129,295 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s); ...@@ -129,15 +129,295 @@ 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 comedi_fasync(int fd, struct file *file, int on);
static int is_device_busy(struct comedi_device *dev); static int is_device_busy(struct comedi_device *dev);
static int resize_async_buffer(struct comedi_device *dev, static int resize_async_buffer(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_subdevice *s,
struct comedi_async *async, unsigned new_size); 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, (int)(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 int new_max_size_kb;
unsigned int new_max_size;
int ret;
struct comedi_subdevice *const read_subdevice =
comedi_get_read_subdevice(info);
ret = kstrtouint(buf, 10, &new_max_size_kb);
if (ret)
return ret;
if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
return -EINVAL;
new_max_size = new_max_size_kb * bytes_per_kibi;
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 DEVICE_ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
show_max_read_buffer_kb, 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 int new_size_kb;
unsigned int new_size;
int retval;
int ret;
struct comedi_subdevice *const read_subdevice =
comedi_get_read_subdevice(info);
ret = kstrtouint(buf, 10, &new_size_kb);
if (ret)
return ret;
if (new_size_kb > (UINT_MAX / bytes_per_kibi))
return -EINVAL;
new_size = new_size_kb * bytes_per_kibi;
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 DEVICE_ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
show_read_buffer_kb, 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 int new_max_size_kb;
unsigned int new_max_size;
int ret;
struct comedi_subdevice *const write_subdevice =
comedi_get_write_subdevice(info);
ret = kstrtouint(buf, 10, &new_max_size_kb);
if (ret)
return ret;
if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
return -EINVAL;
new_max_size = new_max_size_kb * bytes_per_kibi;
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 DEVICE_ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
show_max_write_buffer_kb, 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 int new_size_kb;
unsigned int new_size;
int retval;
int ret;
struct comedi_subdevice *const write_subdevice =
comedi_get_write_subdevice(info);
ret = kstrtouint(buf, 10, &new_size_kb);
if (ret)
return ret;
if (new_size_kb > (UINT_MAX / bytes_per_kibi))
return -EINVAL;
new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
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 DEVICE_ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
show_write_buffer_kb, store_write_buffer_kb);
static struct attribute *comedi_attrs[] = {
&dev_attr_max_read_buffer_kb.attr,
&dev_attr_read_buffer_kb.attr,
&dev_attr_max_write_buffer_kb.attr,
&dev_attr_write_buffer_kb.attr,
NULL
};
/* declarations for sysfs attribute files */ static const struct attribute_group comedi_sysfs_files = {
static struct device_attribute dev_attr_max_read_buffer_kb; .attrs = comedi_attrs,
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;
static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
...@@ -2250,491 +2530,140 @@ int comedi_alloc_board_minor(struct device *hardware_device) ...@@ -2250,491 +2530,140 @@ int comedi_alloc_board_minor(struct device *hardware_device)
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i); MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
if (!IS_ERR(csdev)) if (!IS_ERR(csdev))
info->device->class_dev = csdev; info->device->class_dev = csdev;
dev_set_drvdata(csdev, info); 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;
}
void comedi_free_board_minor(unsigned minor)
{
struct comedi_device_file_info *info;
BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[minor];
comedi_file_info_table[minor] = NULL;
spin_unlock(&comedi_file_info_table_lock);
if (info) {
struct comedi_device *dev = info->device;
if (dev) {
if (dev->class_dev) {
device_destroy(comedi_class,
MKDEV(COMEDI_MAJOR, dev->minor));
}
comedi_device_cleanup(dev);
kfree(dev);
}
kfree(info);
}
}
int comedi_find_board_minor(struct device *hardware_device)
{
int minor;
struct comedi_device_file_info *info;
for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[minor];
if (info && info->hardware_device == hardware_device) {
spin_unlock(&comedi_file_info_table_lock);
return minor;
}
spin_unlock(&comedi_file_info_table_lock);
}
return -ENODEV;
}
int comedi_alloc_subdevice_minor(struct comedi_device *dev,
struct comedi_subdevice *s)
{
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)
return -ENOMEM;
info->device = dev;
info->read_subdevice = s;
info->write_subdevice = s;
spin_lock(&comedi_file_info_table_lock);
for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
if (comedi_file_info_table[i] == NULL) {
comedi_file_info_table[i] = info;
break;
}
}
spin_unlock(&comedi_file_info_table_lock);
if (i == COMEDI_NUM_MINORS) {
kfree(info);
printk(KERN_ERR
"comedi: error: "
"ran out of minor numbers for board device files.\n");
return -EBUSY;
}
s->minor = i;
csdev = device_create(comedi_class, dev->class_dev,
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
dev->minor, (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;
}
void comedi_free_subdevice_minor(struct comedi_subdevice *s)
{
struct comedi_device_file_info *info;
if (s == NULL)
return;
if (s->minor < 0)
return;
BUG_ON(s->minor >= COMEDI_NUM_MINORS);
BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[s->minor];
comedi_file_info_table[s->minor] = NULL;
spin_unlock(&comedi_file_info_table_lock);
if (s->class_dev) {
device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
s->class_dev = NULL;
}
kfree(info);
}
struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
{
struct comedi_device_file_info *info;
BUG_ON(minor >= COMEDI_NUM_MINORS);
spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[minor];
spin_unlock(&comedi_file_info_table_lock);
return info;
}
EXPORT_SYMBOL_GPL(comedi_get_device_file_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, (int)(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 int new_max_size_kb;
unsigned int new_max_size;
int ret;
struct comedi_subdevice *const read_subdevice =
comedi_get_read_subdevice(info);
ret = kstrtouint(buf, 10, &new_max_size_kb);
if (ret)
return ret;
if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
return -EINVAL;
new_max_size = new_max_size_kb * bytes_per_kibi;
mutex_lock(&info->device->mutex); retval = sysfs_create_group(&csdev->kobj, &comedi_sysfs_files);
if (read_subdevice == NULL || if (retval) {
(read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || printk(KERN_ERR
read_subdevice->async == NULL) { "comedi: failed to create sysfs attribute files\n");
mutex_unlock(&info->device->mutex); comedi_free_board_minor(i);
return -EINVAL; return retval;
} }
read_subdevice->async->max_bufsize = new_max_size;
mutex_unlock(&info->device->mutex);
return count; return i;
} }
static struct device_attribute dev_attr_max_read_buffer_kb = { void comedi_free_board_minor(unsigned minor)
.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;
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); BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
if (read_subdevice && spin_lock(&comedi_file_info_table_lock);
(read_subdevice->subdev_flags & SDF_CMD_READ) && info = comedi_file_info_table[minor];
read_subdevice->async) { comedi_file_info_table[minor] = NULL;
buffer_size_kb = read_subdevice->async->prealloc_bufsz / spin_unlock(&comedi_file_info_table_lock);
bytes_per_kibi;
}
retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
mutex_unlock(&info->device->mutex);
return retval; if (info) {
struct comedi_device *dev = info->device;
if (dev) {
if (dev->class_dev) {
device_destroy(comedi_class,
MKDEV(COMEDI_MAJOR, dev->minor));
}
comedi_device_cleanup(dev);
kfree(dev);
}
kfree(info);
}
} }
static ssize_t store_read_buffer_kb(struct device *dev, int comedi_find_board_minor(struct device *hardware_device)
struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct comedi_device_file_info *info = dev_get_drvdata(dev); int minor;
unsigned int new_size_kb; struct comedi_device_file_info *info;
unsigned int new_size;
int retval;
int ret;
struct comedi_subdevice *const read_subdevice =
comedi_get_read_subdevice(info);
ret = kstrtouint(buf, 10, &new_size_kb);
if (ret)
return ret;
if (new_size_kb > (UINT_MAX / bytes_per_kibi))
return -EINVAL;
new_size = new_size_kb * bytes_per_kibi;
mutex_lock(&info->device->mutex); for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
if (read_subdevice == NULL || spin_lock(&comedi_file_info_table_lock);
(read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || info = comedi_file_info_table[minor];
read_subdevice->async == NULL) { if (info && info->hardware_device == hardware_device) {
mutex_unlock(&info->device->mutex); spin_unlock(&comedi_file_info_table_lock);
return -EINVAL; return minor;
} }
retval = resize_async_buffer(info->device, read_subdevice, spin_unlock(&comedi_file_info_table_lock);
read_subdevice->async, new_size); }
mutex_unlock(&info->device->mutex); return -ENODEV;
if (retval < 0)
return retval;
return count;
} }
static struct device_attribute dev_attr_read_buffer_kb = { int comedi_alloc_subdevice_minor(struct comedi_device *dev,
.attr = { struct comedi_subdevice *s)
.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;
struct comedi_device_file_info *info = dev_get_drvdata(dev); struct device *csdev;
unsigned max_buffer_size_kb = 0; unsigned i;
struct comedi_subdevice *const write_subdevice = int retval;
comedi_get_write_subdevice(info);
mutex_lock(&info->device->mutex); info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
if (write_subdevice && if (info == NULL)
(write_subdevice->subdev_flags & SDF_CMD_WRITE) && return -ENOMEM;
write_subdevice->async) { info->device = dev;
max_buffer_size_kb = write_subdevice->async->max_bufsize / info->read_subdevice = s;
bytes_per_kibi; info->write_subdevice = s;
spin_lock(&comedi_file_info_table_lock);
for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
if (comedi_file_info_table[i] == NULL) {
comedi_file_info_table[i] = info;
break;
} }
retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); }
mutex_unlock(&info->device->mutex); spin_unlock(&comedi_file_info_table_lock);
if (i == COMEDI_NUM_MINORS) {
kfree(info);
printk(KERN_ERR
"comedi: error: "
"ran out of minor numbers for board device files.\n");
return -EBUSY;
}
s->minor = i;
csdev = device_create(comedi_class, dev->class_dev,
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
dev->minor, (int)(s - dev->subdevices));
if (!IS_ERR(csdev))
s->class_dev = csdev;
dev_set_drvdata(csdev, info);
retval = sysfs_create_group(&csdev->kobj, &comedi_sysfs_files);
if (retval) {
printk(KERN_ERR
"comedi: failed to create sysfs attribute files\n");
comedi_free_subdevice_minor(s);
return retval; return retval;
}
return i;
} }
static ssize_t store_max_write_buffer_kb(struct device *dev, void comedi_free_subdevice_minor(struct comedi_subdevice *s)
struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct comedi_device_file_info *info = dev_get_drvdata(dev); struct comedi_device_file_info *info;
unsigned int new_max_size_kb;
unsigned int new_max_size;
int ret;
struct comedi_subdevice *const write_subdevice =
comedi_get_write_subdevice(info);
ret = kstrtouint(buf, 10, &new_max_size_kb);
if (ret)
return ret;
if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
return -EINVAL;
new_max_size = new_max_size_kb * bytes_per_kibi;
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; if (s == NULL)
} return;
if (s->minor < 0)
return;
static struct device_attribute dev_attr_max_write_buffer_kb = { BUG_ON(s->minor >= COMEDI_NUM_MINORS);
.attr = { BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
.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, spin_lock(&comedi_file_info_table_lock);
struct device_attribute *attr, char *buf) info = comedi_file_info_table[s->minor];
{ comedi_file_info_table[s->minor] = NULL;
ssize_t retval; spin_unlock(&comedi_file_info_table_lock);
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 (s->class_dev) {
if (write_subdevice && device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
(write_subdevice->subdev_flags & SDF_CMD_WRITE) && s->class_dev = NULL;
write_subdevice->async) {
buffer_size_kb = write_subdevice->async->prealloc_bufsz /
bytes_per_kibi;
} }
retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); kfree(info);
mutex_unlock(&info->device->mutex);
return retval;
} }
static ssize_t store_write_buffer_kb(struct device *dev, struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct comedi_device_file_info *info = dev_get_drvdata(dev); struct comedi_device_file_info *info;
unsigned int new_size_kb;
unsigned int new_size;
int retval;
int ret;
struct comedi_subdevice *const write_subdevice =
comedi_get_write_subdevice(info);
ret = kstrtouint(buf, 10, &new_size_kb);
if (ret)
return ret;
if (new_size_kb > (UINT_MAX / bytes_per_kibi))
return -EINVAL;
new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
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) BUG_ON(minor >= COMEDI_NUM_MINORS);
return retval; spin_lock(&comedi_file_info_table_lock);
return count; info = comedi_file_info_table[minor];
spin_unlock(&comedi_file_info_table_lock);
return info;
} }
EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
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
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment