Commit 1909729e authored by Philippe Gerum's avatar Philippe Gerum

cobalt/rtdm, kernel/drivers: split device class / instance abstractions

How devices are described for registration with rtdm_dev_register() is
significantly modified, affecting both named and protocol device
drivers exactly the same way. Aside of fixing consistency issues, the
bulk of changes is aimed at narrowing the gap between the regular
Linux device driver model and RTDM.

RTDM now shares the Linux namespace for named devices, which are
backed by common character device objects from the regular Linux
device model. As a consequence of this, file descriptors obtained on
named RTDM devices are regular file descriptors on real chrdevs,
visible from the /proc/<pid>/fd interface.

The major change required for supporting this closer integration of
RTDM into the regular Linux driver model involved splitting the device
class properties from the device instance definitions, which used to
be combined in Xenomai 2.x into the rtdm_device descriptor.

A new rtdm_device_class descriptor is introduced, for describing the
general static properties of the devices exposed by a
driver. rtdm_device now represents an instance of such class.

rtdm_device objects link to the descriptor of the rtdm_device class
they belong to.

Hotplug support
---------------

RTDM first allocates and reserves a major and a range of device minors
when the first device of a named device class is registered via
rtdm_dev_register(). Up to class->device_count minors will be
reserved. Minor number are assigned to devices in order of
registration, starting from minor #0.

Device nodes for named RTDM devices are automatically visible from the
/dev/rtdm/ hierarchy with hotplug-enabled device fs (DEVTMPFS now
recommended).
parent 86a5cc0b
......@@ -43,7 +43,7 @@ static inline int a4l_get_minor(struct a4l_device_context *cxt)
/* Get a pointer on the container structure */
struct rtdm_fd *fd = rtdm_private_to_fd(cxt);
/* Get the minor index */
return rtdm_fd_device(fd)->device_id;
return rtdm_fd_minor(fd);
}
#endif /* !_COBALT_RTDM_ANALOGY_CONTEXT_H */
......@@ -27,7 +27,7 @@
#include <asm/atomic.h>
#include <linux/list.h>
#include <linux/cdev.h>
#include <xenomai/version.h>
#include <cobalt/kernel/heap.h>
#include <cobalt/kernel/sched.h>
......@@ -51,7 +51,7 @@
#endif /* CONFIG_PCI */
#include <asm/xenomai/syscall.h>
struct rtdm_dev_context;
struct class;
typedef struct xnselector rtdm_selector_t;
enum rtdm_selecttype;
......@@ -81,23 +81,17 @@ enum rtdm_selecttype;
/** Mask selecting the device type. */
#define RTDM_DEVICE_TYPE_MASK 0x00F0
/** Flag indicating a secure variant of RTDM (not supported here) */
#define RTDM_SECURE_DEVICE 0x80000000
/** @} Device Flags */
/*!
* @anchor drv_versioning @name Driver Versioning
* Current revisions of RTDM structures, encoding of driver versions. See
* Encoding of driver versions. See
* @ref rtdm_api_versioning "API Versioning" for the interface revision.
* @{
*/
/** Version of struct rtdm_device */
#define RTDM_DEVICE_STRUCT_VER 7
/** Version of struct rtdm_dev_context */
#define RTDM_CONTEXT_STRUCT_VER 4
/** Flag indicating a secure variant of RTDM (not supported here) */
#define RTDM_SECURE_DEVICE 0x80000000
/** Version code constructor for driver revisions */
#define RTDM_DRIVER_VER(major, minor, patch) \
(((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF))
......@@ -138,10 +132,6 @@ enum rtdm_selecttype {
/** @} rtdm_sync */
struct rtdm_devctx_reserved {
void (*close)(struct rtdm_fd *fd);
};
/**
* @brief Device context
*
......@@ -149,9 +139,9 @@ struct rtdm_devctx_reserved {
* RTDM takes care of its creation and destruction and passes it to the
* operation handlers when being invoked.
*
* Drivers can attach arbitrary data immediately after the official structure.
* The size of this data is provided via rtdm_device.context_size during
* device registration.
* Drivers can attach arbitrary data immediately after the official
* structure. The size of this data is provided via
* rtdm_device_class.context_size during device registration.
*/
struct rtdm_dev_context {
struct rtdm_fd fd;
......@@ -160,9 +150,6 @@ struct rtdm_dev_context {
/** Reference to owning device */
struct rtdm_device *device;
/** Data stored by RTDM inside a device context (internal use only) */
struct rtdm_devctx_reserved reserved;
/** Begin of driver defined context data structure */
char dev_private[0];
};
......@@ -183,7 +170,7 @@ static inline struct rtdm_dev_context *rtdm_fd_to_context(struct rtdm_fd *fd)
*/
static inline void *rtdm_fd_to_private(struct rtdm_fd *fd)
{
return (void *)rtdm_fd_to_context(fd)->dev_private;
return &rtdm_fd_to_context(fd)->dev_private[0];
}
/**
......@@ -227,79 +214,158 @@ static inline struct rtdm_device *rtdm_fd_device(struct rtdm_fd *fd)
return rtdm_fd_to_context(fd)->device;
}
struct rtdm_dev_reserved {
unsigned magic;
union {
struct {
struct list_head entry;
xnhandle_t handle;
};
struct xnid id;
};
atomic_t refcount;
struct rtdm_dev_context *exclusive_context;
void (*close)(struct rtdm_fd *);
};
/**
* @brief RTDM profile information
*
* This descriptor details the profile information associated to a
* RTDM device class.
*
* @anchor rtdm_profile_info @name RTDM profile information descriptor
*/
struct rtdm_profile_info {
/** Device class name */
const char *name;
/** Device class ID, see @ref RTDM_CLASS_xxx */
int class_id;
/** Device sub-class, see RTDM_SUBCLASS_xxx definition in the
* @ref rtdm_profiles "Device Profiles" */
int subclass_id;
/** Supported device profile version */
int version;
/** Reserved */
unsigned int magic;
};
/**
* @brief RTDM device
* @brief RTDM device class
*
* This structure specifies a RTDM device. As some fields, especially
* the reserved area, will be modified by RTDM during runtime, the
* structure must not reside in write-protected memory.
* This descriptor describes a RTDM device class. The structure holds
* runtime data, therefore it must reside in writable memory.
*/
struct rtdm_device {
/** Data stored by RTDM inside a registered device (internal use only) */
struct rtdm_dev_reserved reserved;
/** Revision number of this structure, see
* @ref drv_versioning "Driver Versioning" defines */
int struct_version;
struct rtdm_device_class {
/**
* Class profile information. The RTDM_PROFILE_INFO() macro @b
* must be used for filling up this field.
*/
struct rtdm_profile_info profile_info;
/** Device flags, see @ref dev_flags "Device Flags" for details */
int device_flags;
/** Size of driver defined appendix to struct rtdm_dev_context */
size_t context_size;
/** Named device identification (orthogonal to Linux device name space) */
char device_name[RTDM_MAX_DEVNAME_LEN + 1];
/** Protocol device identification: protocol family (PF_xxx) */
int protocol_family;
/** Protocol device identification: socket type (SOCK_xxx) */
int socket_type;
/** I/O operation handlers */
struct rtdm_fd_ops ops;
/** Device class ID, see @ref RTDM_CLASS_xxx */
int device_class;
/** Device sub-class, see RTDM_SUBCLASS_xxx definition in the
* @ref rtdm_profiles "Device Profiles" */
int device_sub_class;
/** Supported device profile version */
int profile_version;
/** Informational driver name (reported via /proc) */
const char *driver_name;
/** Driver version, see @ref drv_versioning "Driver Versioning" defines */
/** Driver version, see @ref drv_versioning "Driver Versioning" macros */
int driver_version;
/** Informational peripheral name the device is attached to
* (reported via /proc) */
const char *peripheral_name;
/** Informational driver provider name (reported via /proc) */
const char *provider_name;
/** Name of /proc entry for the device, must not be NULL */
const char *proc_name;
#ifdef CONFIG_XENO_OPT_VFILE
/** Set to device's vfile data after registration, do not modify */
struct xnvfile_directory vfroot;
struct xnvfile_regular info_vfile;
#endif
/** Driver definable device ID */
int device_id;
/** I/O operation handlers */
struct rtdm_fd_ops ops;
/** Count of devices which belong to this class. */
int device_count;
/** Reserved area */
struct {
union {
struct {
struct cdev cdev;
struct class *kclass;
int major;
} named;
};
atomic_t refcount;
};
};
#define RTDM_CLASS_MAGIC 0x8284636c
/**
* @brief Initializer for class profile information.
*
* This macro must be used to fill in the @ref rtdm_profile_info
* "class profile information" field from a RTDM device class.
*
* @param __name Class name (unquoted).
*
* @param __id Class major identification number
* (profile_version.class_id).
*
* @param __subid Class minor identification number
* (profile_version.subclass_id).
*
* @param __version Profile version number.
*
* @note See @ref rtdm_profiles "Device Profiles".
*/
#define RTDM_PROFILE_INFO(__name, __id, __subid, __version) \
{ \
.name = ( # __name ), \
.class_id = (__id), \
.subclass_id = (__subid), \
.version = (__version), \
.magic = ~RTDM_CLASS_MAGIC, \
}
/**
* @brief RTDM device
*
* This descriptor describes a RTDM device instance. The structure
* holds runtime data, therefore it must reside in writable memory.
*/
struct rtdm_device {
/** Device class. */
struct rtdm_device_class *class;
/** Driver definable device data */
void *device_data;
/**
* Device label template for composing the device name. A
* limited printf-like format string is assumed, with a
* provision for replacing the first %d/%i placeholder found
* in the string by the device minor number. It is up to the
* driver to actually mention this placeholder or not,
* depending on the naming convention for its devices. For
* named devices, the corresponding device node will
* automatically appear in the /dev/rtdm hierachy with
* hotplug-enabled device filesystems (DEVTMPFS).
*/
const char *label;
/** Reserved area. */
struct {
unsigned int magic;
char *name;
union {
struct {
struct list_head entry;
xnhandle_t handle;
int minor;
} named;
struct {
struct xnid id;
} proto;
};
atomic_t refcount;
struct rtdm_dev_context *exclusive_context;
struct rtdm_fd_ops ops;
#ifdef CONFIG_XENO_OPT_VFILE
struct xnvfile_directory vfroot;
struct xnvfile_regular info_vfile;
#endif
};
};
/** @} devregister */
/* --- device registration --- */
int rtdm_dev_register(struct rtdm_device *device);
int rtdm_dev_unregister(struct rtdm_device *device, unsigned int poll_delay);
int rtdm_dev_unregister(struct rtdm_device *device,
unsigned int poll_delay);
/* --- inter-driver API --- */
......
......@@ -129,10 +129,10 @@
* the memory region array as follows:
*
* @code
* static struct udd_device udd;
*
* static int foocard_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
* {
* struct udd_device udd;
*
* udd.device_name = "foocard";
* ...
* udd.mem_regions[2].name = "ADC";
......@@ -189,7 +189,10 @@ struct udd_memregion {
* mini-driver when registering via a call to udd_register_device().
*/
struct udd_device {
/** Name of the device managed by the mini-driver. */
/**
* Name of the device managed by the mini-driver, appears
* automatically in the /dev namespace upon creation.
*/
const char *device_name;
/**
* Additional device flags (e.g. RTDM_EXCLUSIVE,
......@@ -289,7 +292,9 @@ struct udd_device {
atomic_t event;
struct udd_signotify signfy;
struct rtdm_event pulse;
struct rtdm_device_class class;
struct rtdm_device device;
struct rtdm_device_class mapper_class;
struct rtdm_device mapper;
char *mapper_name;
int nr_maps;
......
......@@ -20,7 +20,6 @@
#include <linux/err.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/fdtable.h>
#include <linux/anon_inodes.h>
#include <cobalt/kernel/ppd.h>
......@@ -30,48 +29,6 @@
#include "clock.h"
#include "io.h"
static inline void warn_user(const char *name)
{
#ifdef CONFIG_XENO_OPT_DEBUG_USER
printk(XENO_WARN "%s[%d] called regular %s() with RTDM file/socket\n",
current->comm, current->pid, name + 5);
#endif
}
static ssize_t dumb_read(struct file *file, char __user *buf,
size_t count, loff_t __user *ppos)
{
warn_user(__func__);
return -EINVAL;
}
static ssize_t dumb_write(struct file *file, const char __user *buf,
size_t count, loff_t __user *ppos)
{
warn_user(__func__);
return -EINVAL;
}
static unsigned int dumb_poll(struct file *file, poll_table *pt)
{
warn_user(__func__);
return -EINVAL;
}
static long dumb_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
warn_user(__func__);
return -EINVAL;
}
const struct file_operations rtdm_dumb_fops = {
.read = dumb_read,
.write = dumb_write,
.poll = dumb_poll,
.unlocked_ioctl = dumb_ioctl,
};
COBALT_SYSCALL(open, lostage,
int, (const char __user *u_path, int oflag))
{
......
......@@ -209,65 +209,80 @@ static int sysmem_ioctl_nrt(struct rtdm_fd *fd,
return do_sysmem_ioctls(fd, request, arg);
}
static struct rtdm_device private_umm_device = {
.struct_version = RTDM_DEVICE_STRUCT_VER,
.device_flags = RTDM_NAMED_DEVICE,
.context_size = 0,
static struct rtdm_device_class private_umm = {
.profile_info = RTDM_PROFILE_INFO(private_umm,
RTDM_CLASS_MEMORY,
UMM_PRIVATE,
0),
.device_flags = RTDM_NAMED_DEVICE,
.device_count = 1,
.context_size = 0,
.ops = {
.ioctl_rt = umm_ioctl_rt,
.ioctl_nrt = umm_ioctl_nrt,
.mmap = umm_mmap,
.get_unmapped_area = umm_get_unmapped_area,
},
.device_class = RTDM_CLASS_MEMORY,
.device_sub_class = UMM_PRIVATE,
.device_name = COBALT_MEMDEV_PRIVATE,
.driver_name = "memdev",
.driver_version = RTDM_DRIVER_VER(1, 0, 0),
.peripheral_name = "Private user-mapped heap",
.proc_name = private_umm_device.device_name,
.provider_name = "Philippe Gerum <rpm@xenomai.org>",
};
static struct rtdm_device shared_umm_device = {
.struct_version = RTDM_DEVICE_STRUCT_VER,
.device_flags = RTDM_NAMED_DEVICE,
.context_size = 0,
static struct rtdm_device private_umm_device = {
.class = &private_umm,
.label = COBALT_MEMDEV_PRIVATE,
};
static struct rtdm_device_class shared_umm = {
.profile_info = RTDM_PROFILE_INFO(shared_umm,
RTDM_CLASS_MEMORY,
UMM_SHARED,
0),
.device_flags = RTDM_NAMED_DEVICE,
.device_count = 1,
.context_size = 0,
.ops = {
.ioctl_rt = umm_ioctl_rt,
.ioctl_nrt = umm_ioctl_nrt,
.mmap = umm_mmap,
.get_unmapped_area = umm_get_unmapped_area,
},
.device_class = RTDM_CLASS_MEMORY,
.device_sub_class = UMM_SHARED,
.device_name = COBALT_MEMDEV_SHARED,
.driver_name = "memdev",
.driver_version = RTDM_DRIVER_VER(1, 0, 0),
.peripheral_name = "Shared user-mapped heap",
.proc_name = shared_umm_device.device_name,
.provider_name = "Philippe Gerum <rpm@xenomai.org>",
};
static struct rtdm_device sysmem_device = {
.struct_version = RTDM_DEVICE_STRUCT_VER,
.device_flags = RTDM_NAMED_DEVICE,
.context_size = 0,
static struct rtdm_device shared_umm_device = {
.class = &shared_umm,
.label = COBALT_MEMDEV_SHARED,
};
static struct rtdm_device_class sysmem = {
.profile_info = RTDM_PROFILE_INFO(sysmem,
RTDM_CLASS_MEMORY,
SYS_GLOBAL,
0),
.device_flags = RTDM_NAMED_DEVICE,
.device_count = 1,
.context_size = 0,
.ops = {
.open = sysmem_open,
.ioctl_rt = sysmem_ioctl_rt,
.ioctl_nrt = sysmem_ioctl_nrt,
},
.device_class = RTDM_CLASS_MEMORY,
.device_sub_class = SYS_GLOBAL,
.device_name = COBALT_MEMDEV_SYS,
.driver_name = "memdev",
.driver_version = RTDM_DRIVER_VER(1, 0, 0),
.peripheral_name = "System memory heap",
.proc_name = sysmem_device.device_name,
.provider_name = "Philippe Gerum <rpm@xenomai.org>",
};
static struct rtdm_device sysmem_device = {
.class = &sysmem,
.label = COBALT_MEMDEV_SYS,
};
static inline void init_vdso(void)
{
nkvdso->features = XNVDSO_FEATURES;
......
......@@ -44,7 +44,7 @@ static void cleanup_instance(struct rtdm_device *device,
struct rtdm_dev_context *context)
{
if (context) {
if (device->reserved.exclusive_context)
if (device->exclusive_context)
context->device = NULL;
else
kfree(context);
......@@ -56,9 +56,13 @@ static void cleanup_instance(struct rtdm_device *device,
void __rt_dev_close(struct rtdm_fd *fd)
{
struct rtdm_dev_context *context = rtdm_fd_to_context(fd);
if (context->reserved.close)
context->reserved.close(fd);
cleanup_instance(context->device, context);
struct rtdm_device *device = context->device;
struct rtdm_device_class *class = device->class;
if (class->ops.close)
class->ops.close(fd);
cleanup_instance(device, context);
}
void __rt_dev_unref(struct rtdm_fd *fd, unsigned int idx)
......@@ -75,8 +79,8 @@ void __rt_dev_unref(struct rtdm_fd *fd, unsigned int idx)
}
static int create_instance(struct xnsys_ppd *p, int fd,
struct rtdm_device *device,
struct rtdm_dev_context **context_ptr)
struct rtdm_device *device,
struct rtdm_dev_context **context_ptr)
{
struct rtdm_dev_context *context;
spl_t s;
......@@ -103,7 +107,7 @@ static int create_instance(struct xnsys_ppd *p, int fd,
xnlock_put_irqrestore(&rt_fildes_lock, s);
}
context = device->reserved.exclusive_context;
context = device->exclusive_context;
if (context) {
xnlock_get_irqsave(&rt_dev_lock, s);
......@@ -118,7 +122,7 @@ static int create_instance(struct xnsys_ppd *p, int fd,
xnlock_put_irqrestore(&rt_dev_lock, s);
} else {
context = kmalloc(sizeof(struct rtdm_dev_context) +
device->context_size, GFP_KERNEL);
device->class->context_size, GFP_KERNEL);
if (unlikely(context == NULL)) {
err = -ENOMEM;
goto fail;
......@@ -127,7 +131,6 @@ static int create_instance(struct xnsys_ppd *p, int fd,
context->device = device;
}
context->reserved.close = device->reserved.close;
*context_ptr = context;
err = rtdm_fd_enter(p, &context->fd, fd, RTDM_FD_MAGIC, &device->ops);
......@@ -165,7 +168,10 @@ int __rt_dev_open(struct xnsys_ppd *p, int ufd, const char *path, int oflag)
goto cleanup_out;
ufd = ret;
context->fd.minor = minor;
if (device->class->device_flags & RTDM_NAMED_DEVICE)
context->fd.minor = device->named.minor;
else
context->fd.minor = minor;
trace_cobalt_fd_open(current, &context->fd, ufd, oflag);
......@@ -191,8 +197,8 @@ EXPORT_SYMBOL_GPL(__rt_dev_open);
int __rt_dev_socket(struct xnsys_ppd *p, int ufd, int protocol_family,
int socket_type, int protocol)
{
struct rtdm_device *device;
struct rtdm_dev_context *context;
struct rtdm_device *device;
int ret;
device = __rtdm_get_protocol_device(protocol_family, socket_type);
......@@ -225,19 +231,20 @@ cleanup_out:
}
EXPORT_SYMBOL_GPL(__rt_dev_socket);
int
__rt_dev_ioctl_fallback(struct rtdm_fd *fd, unsigned int request, void __user *arg)
int __rt_dev_ioctl_fallback(struct rtdm_fd *fd, unsigned int request,
void __user *arg)
{
struct rtdm_device *dev = rtdm_fd_device(fd);
struct rtdm_device *device = rtdm_fd_device(fd);
struct rtdm_device_class *class = device->class;
struct rtdm_device_info dev_info;
if (fd->magic != RTDM_FD_MAGIC || request != RTIOC_DEVICE_INFO)
return -ENOSYS;
dev_info.device_flags = dev->device_flags;
dev_info.device_class = dev->device_class;
dev_info.device_sub_class = dev->device_sub_class;
dev_info.profile_version = dev->profile_version;
dev_info.device_flags = class->device_flags;
dev_info.device_class = class->profile_info.class_id;
dev_info.device_sub_class = class->profile_info.subclass_id;
dev_info.profile_version = class->profile_info.version;
return rtdm_safe_copy_to_user(fd, arg, &dev_info, sizeof(dev_info));
}
......
This diff is collapsed.
......@@ -1700,13 +1700,9 @@ int __rtdm_mmap_from_fdop(struct rtdm_fd *fd, size_t len, off_t offset,
* XXX: A .get_unmapped_area handler must be provided in the
* nommu case. We use this to force the memory management code
* not to share VM regions for distinct areas to map to, as it
* would otherwise do since all requests originate from the
* same file (i.e. from /dev/mem, see do_mmap_pgoff() in the
* nommu case).
*
* We could solve this by implementing a virtual filesystem
* for RTDM devices, which would go a long way toward a better
* integration with the regular device driver model.
* would otherwise do since all requests currently apply to
* the same file (i.e. from /dev/mem, see do_mmap_pgoff() in
* the nommu case).
*/
if (fd->ops->get_unmapped_area)
offset = fd->ops->get_unmapped_area(fd, len, 0, flags);
......
......@@ -21,6 +21,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/kthread.h>
#include <linux/semaphore.h>
#include <cobalt/kernel/registry.h>
......@@ -638,3 +639,45 @@ void rtdm_fd_init(void)
sema_init(&rtdm_fd_cleanup_sem, 0);
kthread_run(fd_cleanup_thread, NULL, "rtdm_fd");
}
static inline void warn_user(const char *name)
{
#ifdef CONFIG_XENO_OPT_DEBUG_USER
printk(XENO_WARN "%s[%d] called regular %s() with RTDM file/socket\n",
current->comm, current->pid, name + 5);
#endif
}
static ssize_t dumb_read(struct file *file, char __user *buf,
size_t count, loff_t __user *ppos)
{
warn_user(__func__);
return -EINVAL;
}
static ssize_t dumb_write(struct file *file, const char __user *buf,
size_t count, loff_t __user *ppos)
{
warn_user(__func__);
return -EINVAL;
}
static unsigned int dumb_poll(struct file *file, poll_table *pt)
{
warn_user(__func__);
return -EINVAL;
}
static long dumb_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
warn_user(__func__);
return -EINVAL;
}
const struct file_operations rtdm_dumb_fops = {
.read = dumb_read,
.write = dumb_write,
.poll = dumb_poll,
.unlocked_ioctl = dumb_ioctl,
};
......@@ -47,7 +47,7 @@ struct rtdm_device *__rtdm_get_protocol_device(int protocol_family, int socket_t
static inline void rtdm_dereference_device(struct rtdm_device *device)
{
atomic_dec(&device->reserved.refcount);
atomic_dec(&device->refcount);
}
int __init rtdm_dev_init(void);
......
......@@ -46,15 +46,14 @@ static void *named_next(struct xnvfile_regular_iterator *it)
struct rtdm_device *device = priv->curr;
struct list_head *next;
next = device->reserved.entry.next;
next = device->named.entry.next;
if (next == &rtdm_named_devices) {
priv->curr = NULL; /* all done. */
goto out;
}
priv->curr = list_entry(next, struct rtdm_device, reserved.entry);
out:
priv->curr = list_entry(next, struct rtdm_device, named.entry);
out:
return priv->curr;
}
......@@ -64,18 +63,18 @@ static void *named_begin(struct xnvfile_regular_iterator *it)
struct rtdm_device *device;
loff_t pos = 0;
list_for_each_entry(device, &rtdm_named_devices, reserved.entry)
list_for_each_entry(device, &rtdm_named_devices, named.entry)
if (pos++ >= it->pos)
break;
if (&device->reserved.entry == &rtdm_named_devices)
if (&device->named.entry == &rtdm_named_devices)
return NULL; /* End of list. */
priv->curr = device; /* Skip head. */
if (pos == 1)
/* Output the header once, only if some device follows. */
xnvfile_puts(it, "Name\t\t\t\tDriver\t\t/proc\n");
xnvfile_puts(it, "Name\t\t\t\tDriver\n");
return priv->curr;
}
......@@ -84,8 +83,8 @@ static int named_show(struct xnvfile_regular_iterator *it, void *data)
{
struct rtdm_device *device = data;
xnvfile_printf(it, "%-31s\t%-15s\t%s\n", device->device_name,
device->driver_name, device->proc_name);
xnvfile_printf(it, "%-31s\t%-15s\n", device-><