]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/proc.c
LinCAN /proc file-system support updated to be compatible even with 3.12+ kernels.
[lincan.git] / lincan / src / proc.c
index 16dda35c982ddb596fa6493c19ebc987118c4fad..34ecc4363ad05bb573d6a299e818124656aea101 100644 (file)
@@ -61,10 +61,130 @@ static int cc=0; /* static counter for each CAN chip */
 static struct canproc_t can_proc_base;
 static struct canproc_t *base=&can_proc_base;
 
-/* The following functions are needed only for kernel version 2.2. Kernel
- * version 2.4 already defines them for us.
- */
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+
+#include <linux/seq_file.h>
+
+#define CAN_PROC_SHOW_SINGLE_OPS_DECLARE(ops_name, show_function) \
+static int ops_name##_open(struct inode *inode, struct file *file) \
+{ \
+       return single_open(file, show_function, PDE_DATA(inode)); \
+} \
+static const struct file_operations ops_name = { \
+       .owner          = THIS_MODULE, \
+       .open           = ops_name##_open, \
+       .read           = seq_read, \
+       .llseek         = seq_lseek, \
+       .release        = single_release, \
+};
+
+typedef struct file_operations can_proc_read_entry_ops_t;
+typedef struct seq_file can_proc_seq_file_t;
+
+static inline void *can_seq_data(can_proc_seq_file_t *sqf)
+{
+       return sqf->private;
+}
+
+#define can_seq_printf seq_printf
+
+struct proc_dir_entry *can_create_proc_read_entry(const char *name,
+       mode_t mode, struct proc_dir_entry *parent,
+       const can_proc_read_entry_ops_t *proc_read_entry_ops, void * data)
+{
+       return proc_create_data(name, mode, parent, proc_read_entry_ops, data);
+}
+
+struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode,
+                                       struct proc_dir_entry *parent)
+{
+       return proc_mkdir_mode(name, mode, parent);
+}
+
+static int can_proc_remove(struct proc_dir_entry *del)
+{
+       if(!del) return -ENODEV;
+       proc_remove(del);
+       return 0;
+}
+
+static inline struct proc_dir_entry *can_proc_symlink(const char *name,
+                struct proc_dir_entry *parent, const char *dest)
+{
+       return proc_symlink(name, parent, dest);
+}
+
+#else /* kernel older than 3.10 */
+
+typedef read_proc_t *can_proc_read_entry_ops_t;
+typedef struct {
+       int len;
+       int limit;
+       char *buf;
+       void *private;
+} can_proc_seq_file_t;
+
+#define CAN_PROC_SHOW_SINGLE_OPS_DECLARE(ops_name, show_function) \
+static int ops_name##_show_wrapper(char *buf, char **start, off_t offset, \
+                int count, int *eof, void *data) \
+{ \
+       can_proc_seq_file_t seq_pos = { .len = 0, .buf = buf, .limit = PAGE_SIZE, \
+                                       .private = data}; \
+       *eof = 1; \
+       show_function(&seq_pos, data); \
+       return seq_pos.len; \
+} \
+const static can_proc_read_entry_ops_t ops_name = ops_name##_show_wrapper;
+
+static inline void *can_seq_data(can_proc_seq_file_t *sqf)
+{
+       return sqf->private;
+}
+
+static inline int can_seq_printf(can_proc_seq_file_t *sqf, const char *f, ...)
+{
+       int ret;
+       va_list args;
+       va_start(args, f);
+       ret = vsnprintf(sqf->buf + sqf->len, sqf->limit - sqf->len, f, args);
+       sqf->len += ret;
+       if (sqf->len > sqf->limit)
+               sqf->len = sqf->limit;
+       va_end(args);
+       return ret;
+}
+
+struct proc_dir_entry *can_create_proc_read_entry(const char *name,
+       mode_t mode, struct proc_dir_entry *parent,
+       const can_proc_read_entry_ops_t *proc_read_entry_ops, void * data)
+{
+       return create_proc_read_entry(name, mode, parent, *proc_read_entry_ops, data);
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0))
+
+struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode,
+                                       struct proc_dir_entry *parent)
+{
+       return create_proc_entry(name, S_IFDIR | mode, parent);
+}
+
+/* This does not fully follow linux 2.4 and 2.6 prototype to simplify 2.2.x compatibility */
+/* The newer kernels use entry name instead of pointer to the entry */
+static int can_proc_remove(struct proc_dir_entry *del)
+{
+       if(!del) return -ENODEV;
+       remove_proc_entry(del->name, del->parent);
+       return 0;
+}
+
+static inline struct proc_dir_entry *can_proc_symlink(const char *name,
+                struct proc_dir_entry *parent, const char *dest)
+{
+       return proc_symlink(name, parent, dest);
+}
+
+#else /* ancient Linux kernel older than 2.3.0 */
 static void can_fill_inode(struct inode *inode, int fill)
 {
        if (fill)
@@ -160,87 +280,9 @@ static inline struct proc_dir_entry *can_proc_symlink(const char *name,
        return entry;
 }
 
-#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))
-
-struct proc_dir_entry *can_create_proc_read_entry(const char *name,
-       mode_t mode, struct proc_dir_entry *parent,
-       read_proc_t *read_proc, void * data)
-{
-       return create_proc_read_entry(name, mode, parent, read_proc, data);
-}
-
-struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode,
-                                       struct proc_dir_entry *parent)
-{
-       return create_proc_entry(name, S_IFDIR | mode, parent);
-}
-
-/* This does not fully follow linux 2.4 and 2.6 prototype to simplify 2.2.x compatibility */
-/* The newer kernels use entry name instead of pointer to the entry */
-static int can_proc_remove(struct proc_dir_entry *del)
-{
-       if(!del) return -ENODEV;
-       remove_proc_entry(del->name, del->parent);
-       return 0;
-}
-
-static inline struct proc_dir_entry *can_proc_symlink(const char *name,
-                struct proc_dir_entry *parent, const char *dest)
-{
-       return proc_symlink(name, parent, dest);
-}
-
-#else /* Linux kernel 3.10+ */
+#endif /* Linux 2.2 - 2.3 kernels */
 
-#include <linux/seq_file.h>
-
-static int can_status_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "dummy CAN can_create_proc_read_entry implementation\n");
-       return 0;
-}
-
-static int can_status_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, can_status_proc_show, PDE_DATA(inode));
-}
-
-static const struct file_operations can_status_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = can_status_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-struct proc_dir_entry *can_create_proc_read_entry(const char *name,
-       mode_t mode, struct proc_dir_entry *parent,
-       void *read_proc, void * data)
-{
-       /*return proc_read_entry(name, mode, parent, read_proc, data);*/
-       return proc_create_data(name, mode, parent, &can_status_proc_fops, data);
-}
-
-struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode,
-                                       struct proc_dir_entry *parent)
-{
-       return proc_mkdir_mode(name, mode, parent);
-}
-
-static int can_proc_remove(struct proc_dir_entry *del)
-{
-       if(!del) return -ENODEV;
-       proc_remove(del);
-       return 0;
-}
-
-static inline struct proc_dir_entry *can_proc_symlink(const char *name,
-                struct proc_dir_entry *parent, const char *dest)
-{
-       return proc_symlink(name, parent, dest);
-}
-
-#endif /* Functions required for kernel 2.2 */
+#endif /* Linux kernel 3.6 and 3.10+ */
 
 /* can_init_procdir registers the entire CAN directory tree recursively at
  * the proc system.
@@ -274,24 +316,21 @@ int can_delete_procdir(void)
        return 0;
 }
 
-static int can_chip_procinfo(char *buf, char **start, off_t offset,
-                int count, int *eof, void *data)
+static int can_chip_procinfo_show(can_proc_seq_file_t *sqf, void *data)
 {
-       struct canchip_t *chip=data;
-       int len=0;
+       struct canchip_t *chip=can_seq_data(sqf);
 
        /* Generic chip info */
-       len += sprintf(buf+len,"type    : %s\n",chip->chip_type);
-       len += sprintf(buf+len,"index   : %d\n",chip->chip_idx);
-       len += sprintf(buf+len,"irq     : %d\n",chip->chip_irq);
-       len += sprintf(buf+len,"addr    : %lu\n",
+       can_seq_printf(sqf, "type    : %s\n",chip->chip_type);
+       can_seq_printf(sqf, "index   : %d\n",chip->chip_idx);
+       can_seq_printf(sqf, "irq     : %d\n",chip->chip_irq);
+       can_seq_printf(sqf, "addr    : %lu\n",
                        can_ioptr2ulong(chip->chip_base_addr));
-       len += sprintf(buf+len,"config  : %s\n",
+       can_seq_printf(sqf, "config  : %s\n",
                        (chip->flags & CHIP_CONFIGURED) ? "yes":"no");
-       len += sprintf(buf+len,"clock   : %ld Hz\n",chip->clock);
-       len += sprintf(buf+len,"baud    : %ld\n",chip->baudrate);
-       len += sprintf(buf+len,"num obj : %d\n",chip->max_objects);
-
+       can_seq_printf(sqf, "clock   : %ld Hz\n",chip->clock);
+       can_seq_printf(sqf, "baud    : %ld\n",chip->baudrate);
+       can_seq_printf(sqf, "num obj : %d\n",chip->max_objects);
 
 #if 0
        /* Chip specific info if available */
@@ -299,10 +338,10 @@ static int can_chip_procinfo(char *buf, char **start, off_t offset,
                len += (chip->chipspecops->get_info)(chip,buf+len);
 #endif
 
-       *eof = 1;
-       return len;
+       return 0;
 }
 
+CAN_PROC_SHOW_SINGLE_OPS_DECLARE(can_chip_procinfo_ops, can_chip_procinfo_show);
 
 int add_channel_to_procdir(struct candevice_t *candev)
 {
@@ -330,7 +369,7 @@ int add_channel_to_procdir(struct candevice_t *candev)
                can_create_proc_read_entry("chip_info",        /* proc entry name */
                                       0,                  /* protection mask, 0->default */
                                       base->channel[cc]->ch_entry,  /* parent dir, NULL->/proc */
-                                      can_chip_procinfo,
+                                      &can_chip_procinfo_ops,
                                       candev->chip[i]);
 
                cc++;