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