Module: xenomai-forge
Branch: next
Commit: e366d3cb7f6a9be29c20aa4c7defea640fa3db41
URL:    
http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=e366d3cb7f6a9be29c20aa4c7defea640fa3db41

Author: Philippe Gerum <r...@xenomai.org>
Date:   Mon Aug 11 20:50:37 2014 +0200

rtdm/device: enable minor numbers with named devices

As RTDM named device drivers have no actual entry in any file system,
we lack the device minor information normally available from i-nodes.

Therefore a rtdm_device struct currently represents a device unit in
practice, although it should represent a device type, within a larger
class. This model does not allow for straightforward management of
multiple units of the same device type dynamically in a driver, with a
single rtdm_device description matching all the units available
onboard.

This patch introduces a simple fully dynamic naming convention by
which an application can request to open() a particular device unit,
using the form:

open("device-name@<minor>", ...);

The open() call first attempts to match the full name verbatim, then
checks for any minor specification, only looking for the device name
in a second attempt to retrieve the rtdm_device descriptor.

Upon success, the minor is stored into the rtdm_fd descriptor
representing the new connection, and made available to the driver code
by the rtdm_fd_minor() accessor. When specified, a valid minor value
shall be positive or zero, otherwise the match fails. The default
minor value is -1, which the driver may safely ignore, or choose to
interpret as a special device master/control channel.

e.g.:

open("/dev/foo@0", ..) => connect to unit #0 of device type "foo"
open("/dev/foo@7", ..) => connect to unit #7 of device type "foo"
open("/dev/foo", ..) => connect to control channel of device "foo"

---

 include/cobalt/kernel/rtdm/fd.h |    6 ++++++
 kernel/cobalt/rtdm/core.c       |    7 +++---
 kernel/cobalt/rtdm/device.c     |   45 +++++++++++++++++++++++++++++++--------
 kernel/cobalt/rtdm/internal.h   |    4 ++--
 kernel/cobalt/rtdm/proc.c       |    6 ++++--
 5 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/include/cobalt/kernel/rtdm/fd.h b/include/cobalt/kernel/rtdm/fd.h
index 954c60f..d395546 100644
--- a/include/cobalt/kernel/rtdm/fd.h
+++ b/include/cobalt/kernel/rtdm/fd.h
@@ -140,6 +140,7 @@ struct rtdm_fd {
        struct rtdm_fd_ops *ops;
        struct xnsys_ppd *cont;
        unsigned int refs;
+       int minor;
        struct list_head cleanup;
 };
 
@@ -155,6 +156,11 @@ static inline struct xnsys_ppd *rtdm_fd_owner(struct 
rtdm_fd *fd)
        return fd->cont;
 }
 
+static inline int rtdm_fd_minor(struct rtdm_fd *fd)
+{
+       return fd->minor;
+}
+
 int rtdm_fd_enter(struct xnsys_ppd *p, struct rtdm_fd *rtdm_fd, int ufd,
                  unsigned int magic, struct rtdm_fd_ops *ops);
 
diff --git a/kernel/cobalt/rtdm/core.c b/kernel/cobalt/rtdm/core.c
index 0ebf2b2..0503dfe 100644
--- a/kernel/cobalt/rtdm/core.c
+++ b/kernel/cobalt/rtdm/core.c
@@ -143,9 +143,9 @@ int __rt_dev_open(struct xnsys_ppd *p, int ufd, const char 
*path, int oflag)
 {
        struct rtdm_device *device;
        struct rtdm_dev_context *context;
-       int ret;
+       int ret, minor;
 
-       device = get_named_device(path);
+       device = __rtdm_get_named_device(path, &minor);
        ret = -ENODEV;
        if (!device)
                goto err_out;
@@ -154,6 +154,7 @@ int __rt_dev_open(struct xnsys_ppd *p, int ufd, const char 
*path, int oflag)
        if (ret < 0)
                goto cleanup_out;
        ufd = ret;
+       context->fd.minor = minor;
 
        trace_cobalt_fd_open(current, &context->fd, ufd, oflag);
 
@@ -184,7 +185,7 @@ int __rt_dev_socket(struct xnsys_ppd *p, int ufd, int 
protocol_family,
        struct rtdm_dev_context *context;
        int ret;
 
-       device = get_protocol_device(protocol_family, socket_type);
+       device = __rtdm_get_protocol_device(protocol_family, socket_type);
        ret = -EAFNOSUPPORT;
        if (!device)
                goto err_out;
diff --git a/kernel/cobalt/rtdm/device.c b/kernel/cobalt/rtdm/device.c
index 547c8f8..a9819cd 100644
--- a/kernel/cobalt/rtdm/device.c
+++ b/kernel/cobalt/rtdm/device.c
@@ -82,25 +82,51 @@ static inline void rtdm_reference_device(struct rtdm_device 
*device)
        atomic_inc(&device->reserved.refcount);
 }
 
-struct rtdm_device *get_named_device(const char *name)
+struct rtdm_device *__rtdm_get_named_device(const char *name, int *minor_r)
 {
        struct rtdm_device *device;
+       const char *p = NULL;
+       int ret, minor = -1;
        xnhandle_t handle;
-       int err;
+       char *base = NULL;
        spl_t s;
 
-       err = xnregistry_bind(name, XN_NONBLOCK, XN_RELATIVE, &handle);
-       if (err == -EWOULDBLOCK)
-               return NULL;
+       /*
+        * First we look for an exact match. If this fails, we look
+        * for a device minor specification. If we find one, we redo
+        * the search only looking for the device base name. The
+        * default minor value is zero.
+        */
+       for (;;) {
+               ret = xnregistry_bind(name, XN_NONBLOCK, XN_RELATIVE, &handle);
+               if (base)
+                       kfree(base);
+               if (ret != -EWOULDBLOCK)
+                       break;
+               if (p)  /* Look for minor only once. */
+                       return NULL;
+               p = strrchr(name, '@');
+               if (p == NULL || p[1] == '\0')
+                       return NULL;
+               ret = kstrtoint(p + 1, 10, &minor);
+               if (ret || minor < 0)
+                       return NULL;
+               base = kstrdup(name, GFP_KERNEL);
+               if (base == NULL)
+                       return NULL;
+               base[p - name] = '\0';
+               name = base;
+       }
 
        xnlock_get_irqsave(&rt_dev_lock, s);
 
        device = xnregistry_lookup(handle, NULL);
        if (device) {
-               if (device->reserved.magic != RTDM_DEVICE_MAGIC)
-                       device = NULL;
-               else
+               if (device->reserved.magic == RTDM_DEVICE_MAGIC) {
                        rtdm_reference_device(device);
+                       *minor_r = minor;
+               } else
+                       device = NULL;
        }
 
        xnlock_put_irqrestore(&rt_dev_lock, s);
@@ -108,7 +134,8 @@ struct rtdm_device *get_named_device(const char *name)
        return device;
 }
 
-struct rtdm_device *get_protocol_device(int protocol_family, int socket_type)
+struct rtdm_device *
+__rtdm_get_protocol_device(int protocol_family, int socket_type)
 {
        struct rtdm_device *device;
        unsigned long long id;
diff --git a/kernel/cobalt/rtdm/internal.h b/kernel/cobalt/rtdm/internal.h
index 47cb862..515f6ba 100644
--- a/kernel/cobalt/rtdm/internal.h
+++ b/kernel/cobalt/rtdm/internal.h
@@ -55,8 +55,8 @@ extern int rtdm_initialised;
 
 void cleanup_process_files(struct rtdm_process *owner);
 int rtdm_no_support(void);
-struct rtdm_device *get_named_device(const char *name);
-struct rtdm_device *get_protocol_device(int protocol_family, int socket_type);
+struct rtdm_device *__rtdm_get_named_device(const char *name, int *minor_r);
+struct rtdm_device *__rtdm_get_protocol_device(int protocol_family, int 
socket_type);
 
 static inline void rtdm_dereference_device(struct rtdm_device *device)
 {
diff --git a/kernel/cobalt/rtdm/proc.c b/kernel/cobalt/rtdm/proc.c
index feb609b..16082fe 100644
--- a/kernel/cobalt/rtdm/proc.c
+++ b/kernel/cobalt/rtdm/proc.c
@@ -187,7 +187,8 @@ static int openfd_show(struct xnvfile_regular_iterator *it, 
void *data)
        struct rtdm_fd *fd;
 
        if (data == NULL) {
-               xnvfile_puts(it, "Index\tLocked\tDevice\t\t\t\tOwner [PID]\n");
+               xnvfile_puts(it, "Index\tLocked\tMinor\tDevice"
+                            "\t\t\t\tOwner [PID]\n");
                return 0;
        }
 
@@ -202,8 +203,9 @@ static int openfd_show(struct xnvfile_regular_iterator *it, 
void *data)
        device = context->device;
        owner = context->reserved.owner;
 
-       xnvfile_printf(it, "%d\t%d\t%-31s %s [%d]\n", i,
+       xnvfile_printf(it, "%d\t%d\t%d\t%-31s %s [%d]\n", i,
                       close_lock_count,
+                      rtdm_fd_minor(fd),
                       (device->device_flags & RTDM_NAMED_DEVICE) ?
                       device->device_name : device->proc_name,
                       owner ? owner->name : "<kernel>",


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to