}
static int resize_async_buffer(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_async *async, unsigned new_size)
+ struct comedi_subdevice *s, unsigned new_size)
{
+ struct comedi_async *async = s->async;
int retval;
if (new_size > async->max_bufsize)
"subdevice is busy, cannot resize buffer\n");
return -EBUSY;
}
- if (comedi_buf_is_mmapped(async)) {
+ if (comedi_buf_is_mmapped(s)) {
dev_dbg(dev->class_dev,
"subdevice is mmapped, cannot resize buffer\n");
return -EBUSY;
mutex_lock(&dev->mutex);
s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
- err = resize_async_buffer(dev, s, s->async, size);
+ err = resize_async_buffer(dev, s, size);
else
err = -EINVAL;
mutex_unlock(&dev->mutex);
mutex_lock(&dev->mutex);
s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
- err = resize_async_buffer(dev, s, s->async, size);
+ err = resize_async_buffer(dev, s, size);
else
err = -EINVAL;
mutex_unlock(&dev->mutex);
comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
if (async) {
- comedi_buf_reset(async);
+ comedi_buf_reset(s);
async->inttrig = NULL;
kfree(async->cmd.chanlist);
async->cmd.chanlist = NULL;
s = &dev->subdevices[i];
if (s->busy)
return 1;
- if (s->async && comedi_buf_is_mmapped(s->async))
+ if (s->async && comedi_buf_is_mmapped(s))
return 1;
}
return -EBUSY;
if (dev->attached) {
struct module *driver_module = dev->driver->module;
+
comedi_device_detach(dev);
module_put(driver_module);
}
}
if (bc.size) {
- retval = resize_async_buffer(dev, s, async, bc.size);
+ retval = resize_async_buffer(dev, s, bc.size);
if (retval < 0)
return retval;
}
return -EACCES;
if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
- bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
- comedi_buf_read_free(async, bi.bytes_read);
+ bi.bytes_read = comedi_buf_read_alloc(s, bi.bytes_read);
+ comedi_buf_read_free(s, bi.bytes_read);
if (comedi_is_subdevice_idle(s) &&
async->buf_write_count == async->buf_read_count) {
if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
bi.bytes_written =
- comedi_buf_write_alloc(async, bi.bytes_written);
- comedi_buf_write_free(async, bi.bytes_written);
+ comedi_buf_write_alloc(s, bi.bytes_written);
+ comedi_buf_write_free(s, bi.bytes_written);
}
copyback_position:
s = &dev->subdevices[cmd->subdev];
if (s->type == COMEDI_SUBD_UNUSED) {
- dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd->subdev);
+ dev_dbg(dev->class_dev, "%d not valid subdevice\n",
+ cmd->subdev);
return -EIO;
}
if (!s->do_cmd || !s->do_cmdtest || !s->async) {
dev_dbg(dev->class_dev,
- "subdevice %d does not support commands\n", cmd->subdev);
+ "subdevice %d does not support commands\n",
+ cmd->subdev);
return -EIO;
}
goto cleanup;
}
- comedi_buf_reset(async);
+ comedi_buf_reset(s);
async->cb_mask =
COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
{
struct comedi_cmd cmd;
struct comedi_subdevice *s;
- unsigned int *chanlist = NULL;
unsigned int __user *user_chanlist;
int ret;
ret = -EFAULT;
}
- kfree(chanlist);
-
return ret;
}
struct comedi_device *dev = file->private_data;
struct comedi_subdevice *s;
struct comedi_async *async;
- struct comedi_buf_map *bm;
+ struct comedi_buf_map *bm = NULL;
unsigned long start = vma->vm_start;
unsigned long size;
int n_pages;
int i;
int retval;
- mutex_lock(&dev->mutex);
+ /*
+ * 'trylock' avoids circular dependency with current->mm->mmap_sem
+ * and down-reading &dev->attach_lock should normally succeed without
+ * contention unless the device is in the process of being attached
+ * or detached.
+ */
+ if (!down_read_trylock(&dev->attach_lock))
+ return -EAGAIN;
if (!dev->attached) {
dev_dbg(dev->class_dev, "no driver attached\n");
}
n_pages = size >> PAGE_SHIFT;
- bm = async->buf_map;
+
+ /* get reference to current buf map (if any) */
+ bm = comedi_buf_map_from_subdev_get(s);
if (!bm || n_pages > bm->n_pages) {
retval = -EINVAL;
goto done;
retval = 0;
done:
- mutex_unlock(&dev->mutex);
+ up_read(&dev->attach_lock);
+ comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */
return retval;
}
if (s && s->async) {
poll_wait(file, &s->async->wait_head, wait);
if (!s->busy || !comedi_is_subdevice_running(s) ||
- comedi_buf_read_n_available(s->async) > 0)
+ comedi_buf_read_n_available(s) > 0)
mask |= POLLIN | POLLRDNORM;
}
s = comedi_write_subdevice(dev, minor);
if (s && s->async) {
- unsigned int bps = bytes_per_sample(s->async->subdevice);
+ unsigned int bps = bytes_per_sample(s);
poll_wait(file, &s->async->wait_head, wait);
- comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
+ comedi_buf_write_alloc(s, s->async->prealloc_bufsz);
if (!s->busy || !comedi_is_subdevice_running(s) ||
- comedi_buf_write_n_allocated(s->async) >= bps)
+ comedi_buf_write_n_allocated(s) >= bps)
mask |= POLLOUT | POLLWRNORM;
}
m = n;
if (async->buf_write_ptr + m > async->prealloc_bufsz)
m = async->prealloc_bufsz - async->buf_write_ptr;
- comedi_buf_write_alloc(async, async->prealloc_bufsz);
- if (m > comedi_buf_write_n_allocated(async))
- m = comedi_buf_write_n_allocated(async);
+ comedi_buf_write_alloc(s, async->prealloc_bufsz);
+ if (m > comedi_buf_write_n_allocated(s))
+ m = comedi_buf_write_n_allocated(s);
if (m < n)
n = m;
n -= m;
retval = -EFAULT;
}
- comedi_buf_write_free(async, n);
+ comedi_buf_write_free(s, n);
count += n;
nbytes -= n;
n = nbytes;
- m = comedi_buf_read_n_available(async);
+ m = comedi_buf_read_n_available(s);
/* printk("%d available\n",m); */
if (async->buf_read_ptr + m > async->prealloc_bufsz)
m = async->prealloc_bufsz - async->buf_read_ptr;
retval = -EFAULT;
}
- comedi_buf_read_alloc(async, n);
- comedi_buf_read_free(async, n);
+ comedi_buf_read_alloc(s, n);
+ comedi_buf_read_free(s, n);
count += n;
nbytes -= n;
if (capable(CAP_NET_ADMIN) && dev->in_request_module)
goto ok;
- dev->in_request_module = true;
-
-#ifdef CONFIG_KMOD
- mutex_unlock(&dev->mutex);
- request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
- mutex_lock(&dev->mutex);
-#endif
-
dev->in_request_module = false;
if (!dev->attached && !capable(CAP_NET_ADMIN)) {
/* create devices files for legacy/manual use */
for (i = 0; i < comedi_num_legacy_minors; i++) {
struct comedi_device *dev;
+
dev = comedi_alloc_board_minor(NULL);
if (IS_ERR(dev)) {
comedi_cleanup_board_minors();