+#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 */