#include "comedi_internal.h"
+#define COMEDI_NUM_MINORS 0x100
+#define COMEDI_NUM_SUBDEVICE_MINORS \
+ (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS)
+
#ifdef CONFIG_COMEDI_DEBUG
int comedi_debug;
EXPORT_SYMBOL(comedi_debug);
struct comedi_device *device;
struct comedi_subdevice *read_subdevice;
struct comedi_subdevice *write_subdevice;
- struct device *hardware_device;
};
-static DEFINE_SPINLOCK(comedi_file_info_table_lock);
-static struct comedi_file_info *comedi_file_info_table[COMEDI_NUM_MINORS];
+static DEFINE_MUTEX(comedi_board_minor_table_lock);
+static struct comedi_file_info
+*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS];
+
+static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
+/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */
+static struct comedi_file_info
+*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];
+
+static struct class *comedi_class;
+static struct cdev comedi_cdev;
+
+static void comedi_device_init(struct comedi_device *dev)
+{
+ spin_lock_init(&dev->spinlock);
+ mutex_init(&dev->mutex);
+ dev->minor = -1;
+}
+
+static void comedi_device_cleanup(struct comedi_device *dev)
+{
+ struct module *driver_module = NULL;
+
+ if (dev == NULL)
+ return;
+ mutex_lock(&dev->mutex);
+ if (dev->attached)
+ driver_module = dev->driver->module;
+ comedi_device_detach(dev);
+ while (dev->use_count > 0) {
+ if (driver_module)
+ module_put(driver_module);
+ module_put(THIS_MODULE);
+ dev->use_count--;
+ }
+ mutex_unlock(&dev->mutex);
+ mutex_destroy(&dev->mutex);
+}
+
+static struct comedi_file_info *comedi_clear_board_minor(unsigned minor)
+{
+ struct comedi_file_info *info;
+
+ mutex_lock(&comedi_board_minor_table_lock);
+ info = comedi_board_minor_table[minor];
+ comedi_board_minor_table[minor] = NULL;
+ mutex_unlock(&comedi_board_minor_table_lock);
+ return info;
+}
+
+static void comedi_free_board_file_info(struct comedi_file_info *info)
+{
+ 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 struct comedi_file_info
+*comedi_file_info_from_board_minor(unsigned minor)
+{
+ struct comedi_file_info *info;
-static struct comedi_file_info *comedi_file_info_from_minor(unsigned minor)
+ BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
+ mutex_lock(&comedi_board_minor_table_lock);
+ info = comedi_board_minor_table[minor];
+ mutex_unlock(&comedi_board_minor_table_lock);
+ return info;
+}
+
+static struct comedi_file_info
+*comedi_file_info_from_subdevice_minor(unsigned minor)
{
struct comedi_file_info *info;
+ unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
- 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);
+ BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
+ mutex_lock(&comedi_subdevice_minor_table_lock);
+ info = comedi_subdevice_minor_table[i];
+ mutex_unlock(&comedi_subdevice_minor_table_lock);
return info;
}
return info ? info->device : NULL;
}
+static struct comedi_device *comedi_dev_from_board_minor(unsigned minor)
+{
+ struct comedi_file_info *info;
+
+ info = comedi_file_info_from_board_minor(minor);
+ return comedi_dev_from_file_info(info);
+}
+
+static struct comedi_device *comedi_dev_from_subdevice_minor(unsigned minor)
+{
+ struct comedi_file_info *info;
+
+ info = comedi_file_info_from_subdevice_minor(minor);
+ return comedi_dev_from_file_info(info);
+}
+
struct comedi_device *comedi_dev_from_minor(unsigned minor)
{
- return comedi_dev_from_file_info(comedi_file_info_from_minor(minor));
+ if (minor < COMEDI_NUM_BOARD_MINORS)
+ return comedi_dev_from_board_minor(minor);
+ else
+ return comedi_dev_from_subdevice_minor(minor);
}
EXPORT_SYMBOL_GPL(comedi_dev_from_minor);
static struct comedi_subdevice *
-comedi_read_subdevice(const struct comedi_file_info *info)
+comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
{
- if (info->read_subdevice)
- return info->read_subdevice;
- if (info->device)
- return info->device->read_subdev;
- return NULL;
+ struct comedi_file_info *info;
+
+ if (minor >= COMEDI_NUM_BOARD_MINORS) {
+ info = comedi_file_info_from_subdevice_minor(minor);
+ if (!info || info->device != dev)
+ return NULL;
+ if (info->read_subdevice)
+ return info->read_subdevice;
+ }
+ return dev->read_subdev;
}
static struct comedi_subdevice *
-comedi_write_subdevice(const struct comedi_file_info *info)
+comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
{
- if (info->write_subdevice)
- return info->write_subdevice;
- if (info->device)
- return info->device->write_subdev;
- return NULL;
+ struct comedi_file_info *info;
+
+ if (minor >= COMEDI_NUM_BOARD_MINORS) {
+ info = comedi_file_info_from_subdevice_minor(minor);
+ if (!info || info->device != dev)
+ return NULL;
+ if (info->write_subdevice)
+ return info->write_subdevice;
+ }
+ return dev->write_subdev;
}
static int resize_async_buffer(struct comedi_device *dev,
/* sysfs attribute files */
-static ssize_t show_max_read_buffer_kb(struct device *dev,
+static ssize_t show_max_read_buffer_kb(struct device *csdev,
struct device_attribute *attr, char *buf)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_read_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size = 0;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
size = s->async->max_bufsize / 1024;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_max_read_buffer_kb(struct device *dev,
+static ssize_t store_max_read_buffer_kb(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_read_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size;
int err;
return -EINVAL;
size *= 1024;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
s->async->max_bufsize = size;
else
err = -EINVAL;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return err ? err : count;
}
-static ssize_t show_read_buffer_kb(struct device *dev,
+static ssize_t show_read_buffer_kb(struct device *csdev,
struct device_attribute *attr, char *buf)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_read_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size = 0;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
size = s->async->prealloc_bufsz / 1024;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_read_buffer_kb(struct device *dev,
+static ssize_t store_read_buffer_kb(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_read_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size;
int err;
return -EINVAL;
size *= 1024;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
- err = resize_async_buffer(info->device, s, s->async, size);
+ err = resize_async_buffer(dev, s, s->async, size);
else
err = -EINVAL;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return err ? err : count;
}
-static ssize_t show_max_write_buffer_kb(struct device *dev,
+static ssize_t show_max_write_buffer_kb(struct device *csdev,
struct device_attribute *attr,
char *buf)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_write_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size = 0;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
size = s->async->max_bufsize / 1024;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_max_write_buffer_kb(struct device *dev,
+static ssize_t store_max_write_buffer_kb(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_write_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size;
int err;
return -EINVAL;
size *= 1024;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
s->async->max_bufsize = size;
else
err = -EINVAL;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return err ? err : count;
}
-static ssize_t show_write_buffer_kb(struct device *dev,
+static ssize_t show_write_buffer_kb(struct device *csdev,
struct device_attribute *attr, char *buf)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_write_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size = 0;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
size = s->async->prealloc_bufsz / 1024;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_write_buffer_kb(struct device *dev,
+static ssize_t store_write_buffer_kb(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_write_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size;
int err;
return -EINVAL;
size *= 1024;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
- err = resize_async_buffer(info->device, s, s->async, size);
+ err = resize_async_buffer(dev, s, s->async, size);
else
err = -EINVAL;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return err ? err : count;
}
struct comedi_devconfig __user *arg)
{
struct comedi_devconfig it;
- int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return -EINVAL;
}
- ret = comedi_device_attach(dev, &it);
- if (ret == 0) {
- if (!try_module_get(dev->driver->module)) {
- comedi_device_detach(dev);
- ret = -ENOSYS;
- }
- }
+ if (dev->minor >= comedi_num_legacy_minors)
+ /* don't re-use dynamically allocated comedi devices */
+ return -EBUSY;
- return ret;
+ /* This increments the driver module count on success. */
+ return comedi_device_attach(dev, &it);
}
/*
struct file *file)
{
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
struct comedi_subdevice *s;
struct comedi_devinfo devinfo;
strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
- s = comedi_read_subdevice(info);
+ s = comedi_read_subdevice(dev, minor);
if (s)
devinfo.read_subdevice = s->index;
else
devinfo.read_subdevice = -1;
- s = comedi_write_subdevice(info);
+ s = comedi_write_subdevice(dev, minor);
if (s)
devinfo.write_subdevice = s->index;
else
unsigned long arg)
{
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
int rc;
if (!dev)
}
rc = do_devconfig_ioctl(dev,
(struct comedi_devconfig __user *)arg);
+ if (rc == 0) {
+ if (arg == 0 &&
+ dev->minor >= comedi_num_legacy_minors) {
+ /* Successfully unconfigured a dynamically
+ * allocated device. Try and remove it. */
+ struct comedi_file_info *info;
+ info = comedi_clear_board_minor(dev->minor);
+ if (info) {
+ mutex_unlock(&dev->mutex);
+ comedi_free_board_file_info(info);
+ return rc;
+ }
+ }
+ }
goto done;
}
static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
{
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
struct comedi_subdevice *s;
struct comedi_async *async;
unsigned long start = vma->vm_start;
}
if (vma->vm_flags & VM_WRITE)
- s = comedi_write_subdevice(info);
+ s = comedi_write_subdevice(dev, minor);
else
- s = comedi_read_subdevice(info);
+ s = comedi_read_subdevice(dev, minor);
if (!s) {
retval = -EINVAL;
goto done;
{
unsigned int mask = 0;
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
struct comedi_subdevice *s;
if (!dev)
goto done;
}
- s = comedi_read_subdevice(info);
+ s = comedi_read_subdevice(dev, minor);
if (s && s->async) {
poll_wait(file, &s->async->wait_head, wait);
if (!s->busy || !comedi_is_subdevice_running(s) ||
mask |= POLLIN | POLLRDNORM;
}
- s = comedi_write_subdevice(info);
+ s = comedi_write_subdevice(dev, minor);
if (s && s->async) {
unsigned int bps = bytes_per_sample(s->async->subdevice);
int n, m, count = 0, retval = 0;
DECLARE_WAITQUEUE(wait, current);
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
if (!dev)
return -ENODEV;
return -ENODEV;
}
- s = comedi_write_subdevice(info);
+ s = comedi_write_subdevice(dev, minor);
if (!s || !s->async)
return -EIO;
int n, m, count = 0, retval = 0;
DECLARE_WAITQUEUE(wait, current);
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
if (!dev)
return -ENODEV;
return -ENODEV;
}
- s = comedi_read_subdevice(info);
+ s = comedi_read_subdevice(dev, minor);
if (!s || !s->async)
return -EIO;
.llseek = noop_llseek,
};
-static struct class *comedi_class;
-static struct cdev comedi_cdev;
-
void comedi_error(const struct comedi_device *dev, const char *s)
{
dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
}
EXPORT_SYMBOL(comedi_event);
-static void comedi_device_init(struct comedi_device *dev)
-{
- spin_lock_init(&dev->spinlock);
- mutex_init(&dev->mutex);
- dev->minor = -1;
-}
-
-static void comedi_device_cleanup(struct comedi_device *dev)
-{
- struct module *driver_module = NULL;
-
- if (dev == NULL)
- return;
- mutex_lock(&dev->mutex);
- if (dev->attached)
- driver_module = dev->driver->module;
- comedi_device_detach(dev);
- while (dev->use_count > 0) {
- if (driver_module)
- module_put(driver_module);
- module_put(THIS_MODULE);
- dev->use_count--;
- }
- mutex_unlock(&dev->mutex);
- mutex_destroy(&dev->mutex);
-}
-
/* Note: the ->mutex is pre-locked on successful return */
struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
{
return ERR_PTR(-ENOMEM);
}
info->device = dev;
- info->hardware_device = hardware_device;
comedi_device_init(dev);
+ comedi_set_hw_dev(dev, hardware_device);
mutex_lock(&dev->mutex);
- spin_lock(&comedi_file_info_table_lock);
+ mutex_lock(&comedi_board_minor_table_lock);
for (i = hardware_device ? comedi_num_legacy_minors : 0;
i < COMEDI_NUM_BOARD_MINORS; ++i) {
- if (comedi_file_info_table[i] == NULL) {
- comedi_file_info_table[i] = info;
+ if (comedi_board_minor_table[i] == NULL) {
+ comedi_board_minor_table[i] = info;
break;
}
}
- spin_unlock(&comedi_file_info_table_lock);
+ mutex_unlock(&comedi_board_minor_table_lock);
if (i == COMEDI_NUM_BOARD_MINORS) {
mutex_unlock(&dev->mutex);
comedi_device_cleanup(dev);
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
if (!IS_ERR(csdev))
dev->class_dev = csdev;
- dev_set_drvdata(csdev, info);
/* Note: dev->mutex needs to be unlocked by the caller. */
return dev;
}
-static struct comedi_file_info *comedi_clear_minor(unsigned minor)
-{
- struct comedi_file_info *info;
-
- 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);
- return info;
-}
-
-static void comedi_free_board_file_info(struct comedi_file_info *info)
-{
- 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 void comedi_free_board_minor(unsigned minor)
{
BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
- comedi_free_board_file_info(comedi_clear_minor(minor));
+ comedi_free_board_file_info(comedi_clear_board_minor(minor));
}
void comedi_release_hardware_device(struct device *hardware_device)
for (minor = comedi_num_legacy_minors; 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) {
- comedi_file_info_table[minor] = NULL;
- spin_unlock(&comedi_file_info_table_lock);
+ mutex_lock(&comedi_board_minor_table_lock);
+ info = comedi_board_minor_table[minor];
+ if (info && info->device->hw_dev == hardware_device) {
+ comedi_board_minor_table[minor] = NULL;
+ mutex_unlock(&comedi_board_minor_table_lock);
comedi_free_board_file_info(info);
break;
}
- spin_unlock(&comedi_file_info_table_lock);
+ mutex_unlock(&comedi_board_minor_table_lock);
}
}
info->read_subdevice = s;
if (s->subdev_flags & SDF_CMD_WRITE)
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;
+ mutex_lock(&comedi_subdevice_minor_table_lock);
+ for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
+ if (comedi_subdevice_minor_table[i] == NULL) {
+ comedi_subdevice_minor_table[i] = info;
break;
}
}
- spin_unlock(&comedi_file_info_table_lock);
- if (i == COMEDI_NUM_MINORS) {
+ mutex_unlock(&comedi_subdevice_minor_table_lock);
+ if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
kfree(info);
pr_err("comedi: error: ran out of minor numbers for subdevice files.\n");
return -EBUSY;
}
+ i += COMEDI_NUM_BOARD_MINORS;
s->minor = i;
csdev = device_create(comedi_class, dev->class_dev,
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
dev->minor, s->index);
if (!IS_ERR(csdev))
s->class_dev = csdev;
- dev_set_drvdata(csdev, info);
return 0;
}
void comedi_free_subdevice_minor(struct comedi_subdevice *s)
{
struct comedi_file_info *info;
+ unsigned int i;
if (s == NULL)
return;
return;
BUG_ON(s->minor >= COMEDI_NUM_MINORS);
- BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
+ BUG_ON(s->minor < COMEDI_NUM_BOARD_MINORS);
- info = comedi_clear_minor(s->minor);
+ i = s->minor - COMEDI_NUM_BOARD_MINORS;
+ mutex_lock(&comedi_subdevice_minor_table_lock);
+ info = comedi_subdevice_minor_table[i];
+ comedi_subdevice_minor_table[i] = NULL;
+ mutex_unlock(&comedi_subdevice_minor_table_lock);
if (s->class_dev) {
device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
s->class_dev = NULL;
int i;
comedi_cleanup_board_minors();
- for (i = 0; i < COMEDI_NUM_MINORS; ++i)
- BUG_ON(comedi_file_info_table[i]);
+ for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i)
+ BUG_ON(comedi_board_minor_table[i]);
+ for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i)
+ BUG_ON(comedi_subdevice_minor_table[i]);
class_destroy(comedi_class);
cdev_del(&comedi_cdev);