Loading drivers/staging/comedi/comedi_fops.c +379 −39 Original line number Original line Diff line number Diff line Loading @@ -44,6 +44,7 @@ #include <linux/fs.h> #include <linux/fs.h> #include "comedidev.h" #include "comedidev.h" #include <linux/cdev.h> #include <linux/cdev.h> #include <linux/stat.h> #include <linux/io.h> #include <linux/io.h> #include <linux/uaccess.h> #include <linux/uaccess.h> Loading Loading @@ -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 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, 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 #ifdef HAVE_UNLOCKED_IOCTL static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, Loading Loading @@ -277,7 +287,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg) struct comedi_bufconfig bc; struct comedi_bufconfig bc; struct comedi_async *async; struct comedi_async *async; struct comedi_subdevice *s; struct comedi_subdevice *s; int ret = 0; int retval = 0; if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) return -EFAULT; return -EFAULT; Loading @@ -303,37 +313,9 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg) } } if (bc.size) { if (bc.size) { if (bc.size > async->max_bufsize) retval = resize_async_buffer(dev, s, async, bc.size); return -EPERM; if (retval < 0) return retval; 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); } } bc.size = async->prealloc_bufsz; bc.size = async->prealloc_bufsz; Loading Loading @@ -2132,6 +2114,7 @@ int comedi_alloc_board_minor(struct device *hardware_device) struct comedi_device_file_info *info; struct comedi_device_file_info *info; struct device *csdev; struct device *csdev; unsigned i; unsigned i; int retval; info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); if (info == NULL) if (info == NULL) Loading @@ -2154,8 +2137,7 @@ int comedi_alloc_board_minor(struct device *hardware_device) comedi_device_cleanup(info->device); comedi_device_cleanup(info->device); kfree(info->device); kfree(info->device); kfree(info); kfree(info); rt_printk printk(KERN_ERR "comedi: error: ran out of minor numbers for board device files.\n"); ("comedi: error: ran out of minor numbers for board device files.\n"); return -EBUSY; return -EBUSY; } } info->device->minor = i; info->device->minor = i; Loading @@ -2164,7 +2146,35 @@ int comedi_alloc_board_minor(struct device *hardware_device) hardware_device, "comedi%i", i); hardware_device, "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); 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; return i; } } Loading Loading @@ -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; unsigned long flags; struct comedi_device_file_info *info; struct comedi_device_file_info *info; struct device *csdev; struct device *csdev; unsigned i; unsigned i; int retval; info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); if (info == NULL) if (info == NULL) Loading @@ -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); comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); if (i == COMEDI_NUM_MINORS) { if (i == COMEDI_NUM_MINORS) { kfree(info); kfree(info); rt_printk printk(KERN_ERR "comedi: error: ran out of minor numbers for board device files.\n"); ("comedi: error: ran out of minor numbers for board device files.\n"); return -EBUSY; return -EBUSY; } } s->minor = i; s->minor = i; Loading @@ -2227,7 +2238,35 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdev (int)(s - dev->subdevices)); (int)(s - dev->subdevices)); if (!IS_ERR(csdev)) if (!IS_ERR(csdev)) s->class_dev = 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; return i; } } Loading Loading @@ -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); comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); return info; 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 }; Loading
drivers/staging/comedi/comedi_fops.c +379 −39 Original line number Original line Diff line number Diff line Loading @@ -44,6 +44,7 @@ #include <linux/fs.h> #include <linux/fs.h> #include "comedidev.h" #include "comedidev.h" #include <linux/cdev.h> #include <linux/cdev.h> #include <linux/stat.h> #include <linux/io.h> #include <linux/io.h> #include <linux/uaccess.h> #include <linux/uaccess.h> Loading Loading @@ -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 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, 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 #ifdef HAVE_UNLOCKED_IOCTL static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, Loading Loading @@ -277,7 +287,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg) struct comedi_bufconfig bc; struct comedi_bufconfig bc; struct comedi_async *async; struct comedi_async *async; struct comedi_subdevice *s; struct comedi_subdevice *s; int ret = 0; int retval = 0; if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) return -EFAULT; return -EFAULT; Loading @@ -303,37 +313,9 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg) } } if (bc.size) { if (bc.size) { if (bc.size > async->max_bufsize) retval = resize_async_buffer(dev, s, async, bc.size); return -EPERM; if (retval < 0) return retval; 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); } } bc.size = async->prealloc_bufsz; bc.size = async->prealloc_bufsz; Loading Loading @@ -2132,6 +2114,7 @@ int comedi_alloc_board_minor(struct device *hardware_device) struct comedi_device_file_info *info; struct comedi_device_file_info *info; struct device *csdev; struct device *csdev; unsigned i; unsigned i; int retval; info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); if (info == NULL) if (info == NULL) Loading @@ -2154,8 +2137,7 @@ int comedi_alloc_board_minor(struct device *hardware_device) comedi_device_cleanup(info->device); comedi_device_cleanup(info->device); kfree(info->device); kfree(info->device); kfree(info); kfree(info); rt_printk printk(KERN_ERR "comedi: error: ran out of minor numbers for board device files.\n"); ("comedi: error: ran out of minor numbers for board device files.\n"); return -EBUSY; return -EBUSY; } } info->device->minor = i; info->device->minor = i; Loading @@ -2164,7 +2146,35 @@ int comedi_alloc_board_minor(struct device *hardware_device) hardware_device, "comedi%i", i); hardware_device, "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); 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; return i; } } Loading Loading @@ -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; unsigned long flags; struct comedi_device_file_info *info; struct comedi_device_file_info *info; struct device *csdev; struct device *csdev; unsigned i; unsigned i; int retval; info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); if (info == NULL) if (info == NULL) Loading @@ -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); comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); if (i == COMEDI_NUM_MINORS) { if (i == COMEDI_NUM_MINORS) { kfree(info); kfree(info); rt_printk printk(KERN_ERR "comedi: error: ran out of minor numbers for board device files.\n"); ("comedi: error: ran out of minor numbers for board device files.\n"); return -EBUSY; return -EBUSY; } } s->minor = i; s->minor = i; Loading @@ -2227,7 +2238,35 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdev (int)(s - dev->subdevices)); (int)(s - dev->subdevices)); if (!IS_ERR(csdev)) if (!IS_ERR(csdev)) s->class_dev = 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; return i; } } Loading Loading @@ -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); comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); return info; 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 };