staging: comedi: add comedi_dev_get_from_minor()
authorIan Abbott <abbotti@mev.co.uk>
Fri, 8 Nov 2013 15:03:33 +0000 (15:03 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Nov 2013 00:16:44 +0000 (16:16 -0800)
Add function `struct comedi_device *comedi_dev_get_from_minor(unsigned
minor)`.  This behaves like the existing `comedi_dev_from_minor()`
except that it also increments the `struct kref refcount` member (via
new helper function `comedi_dev_get()`) to prevent it being freed.  If
it returns a valid pointer, the caller is responsible for calling
`comedi_dev_put()` to decrement the reference count.

Export `comedi_dev_get_from_minor()` and `comedi_dev_put()` as they will
be used by the "kcomedilib" module in addition to the "comedi" module
itself.

Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/comedi/comedi_fops.c
drivers/staging/comedi/comedidev.h

index 403324c895b13af2e5baa07cd43194396f0497df..5e5ddbdbad0b39d1f4ff5310b50d6397c4b4f215 100644 (file)
@@ -111,6 +111,14 @@ int comedi_dev_put(struct comedi_device *dev)
                return kref_put(&dev->refcount, comedi_dev_kref_release);
        return 1;
 }
+EXPORT_SYMBOL_GPL(comedi_dev_put);
+
+static struct comedi_device *comedi_dev_get(struct comedi_device *dev)
+{
+       if (dev)
+               kref_get(&dev->refcount);
+       return dev;
+}
 
 static void comedi_device_cleanup(struct comedi_device *dev)
 {
@@ -209,6 +217,40 @@ struct comedi_device *comedi_dev_from_minor(unsigned minor)
 }
 EXPORT_SYMBOL_GPL(comedi_dev_from_minor);
 
+static struct comedi_device *comedi_dev_get_from_board_minor(unsigned minor)
+{
+       struct comedi_device *dev;
+
+       BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
+       mutex_lock(&comedi_board_minor_table_lock);
+       dev = comedi_dev_get(comedi_board_minor_table[minor]);
+       mutex_unlock(&comedi_board_minor_table_lock);
+       return dev;
+}
+
+static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor)
+{
+       struct comedi_device *dev;
+       struct comedi_subdevice *s;
+       unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
+
+       BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
+       mutex_lock(&comedi_subdevice_minor_table_lock);
+       s = comedi_subdevice_minor_table[i];
+       dev = comedi_dev_get(s ? s->device : NULL);
+       mutex_unlock(&comedi_subdevice_minor_table_lock);
+       return dev;
+}
+
+struct comedi_device *comedi_dev_get_from_minor(unsigned minor)
+{
+       if (minor < COMEDI_NUM_BOARD_MINORS)
+               return comedi_dev_get_from_board_minor(minor);
+       else
+               return comedi_dev_get_from_subdevice_minor(minor);
+}
+EXPORT_SYMBOL_GPL(comedi_dev_get_from_minor);
+
 static struct comedi_subdevice *
 comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
 {
index 08652dfa8c031db7a6ebc3b6243c8ed7919a83d9..a9b1468aa17cd3d5bf800b8438542054acf777b9 100644 (file)
@@ -236,6 +236,8 @@ static const unsigned COMEDI_SUBDEVICE_MINOR_SHIFT = 4;
 static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1;
 
 struct comedi_device *comedi_dev_from_minor(unsigned minor);
+struct comedi_device *comedi_dev_get_from_minor(unsigned minor);
+int comedi_dev_put(struct comedi_device *dev);
 
 void init_polling(void);
 void cleanup_polling(void);