]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/proc.c
The original version of Arnaud Westenberg Linux CAN-bus driver
[lincan.git] / lincan / src / proc.c
diff --git a/lincan/src/proc.c b/lincan/src/proc.c
new file mode 100644 (file)
index 0000000..401148e
--- /dev/null
@@ -0,0 +1,306 @@
+/* proc.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * This software is released under the GPL-License.
+ * Version 0.7  6 Aug 2001
+ */ 
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/autoconf.h>
+#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined (MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <linux/version.h>
+
+#include "../include/main.h"
+#include "../include/proc.h"
+#include "../include/setup.h"
+
+int add_channel_to_procdir(void);
+int remove_channel_from_procdir(void);
+int add_object_to_procdir(void);
+int remove_object_from_procdir(void);
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+static int candev_readlink(struct proc_dir_entry *de, char *page);
+#endif
+
+static int bc=0; /* static counter for each hardware board */
+static int cc=0; /* static counter for each CAN chip */
+static int oc=0; /* static counter for each message object */
+
+struct canproc_t can_proc_base;
+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,2,19))
+static void can_fill_inode(struct inode *inode, int fill)
+{
+       if (fill)
+               MOD_INC_USE_COUNT;
+       else
+               MOD_DEC_USE_COUNT;
+}
+
+static struct proc_dir_entry * new_can_proc_entry(unsigned short inode,
+    const char *name, mode_t mode, nlink_t nlink, struct proc_dir_entry *parent)
+{
+       struct proc_dir_entry *new_entry = NULL;
+
+       new_entry = (struct proc_dir_entry *) kmalloc(sizeof(struct 
+                                               proc_dir_entry), GFP_KERNEL);
+       if (new_entry == NULL)
+               return NULL;
+
+       memset(new_entry, 0, sizeof(struct proc_dir_entry));
+
+       new_entry->low_ino = inode;
+       new_entry->namelen = strlen(name);
+       new_entry->name = name;
+       new_entry->mode = mode;
+       new_entry->nlink = nlink;
+       new_entry->fill_inode = can_fill_inode;
+       new_entry->parent = parent;
+
+       proc_register(parent, new_entry);
+
+       return new_entry;
+}
+
+int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
+{
+       if (del != NULL) {
+               proc_unregister(parent, del->low_ino);
+               kfree(del);
+               del = NULL;
+               return 0;
+       }
+       else return -ENODEV;
+}
+#endif // Functions required for kernel 2.2
+
+/* can_init_procdir registers the entire CAN directory tree recursively at
+ * the proc system.
+ */
+int can_init_procdir(void)
+{
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+       base->can_proc_entry = new_can_proc_entry(0, "can", S_IFDIR | S_IRUGO | 
+                                       S_IXUGO, 0, &proc_root);
+#else
+       base->can_proc_entry = create_proc_entry("can", S_IFDIR | S_IRUGO | 
+                                       S_IXUGO, &proc_root);
+#endif
+       if (base->can_proc_entry == NULL)
+               return -ENODEV;
+
+       for (bc=0; bc<hardware_p->nr_boards; bc++) {
+               add_channel_to_procdir();
+       } 
+
+       return 0;
+}
+
+/* can_delete_procdir removes the entire CAN tree from the proc system */
+int can_delete_procdir(void)
+{
+       if (remove_channel_from_procdir()) 
+               return -ENODEV;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+       if (can_remove_proc_entry(base->can_proc_entry, &proc_root)) 
+               return -ENODEV;
+#else
+       remove_proc_entry("can", &proc_root);
+#endif
+
+       return 0;
+}
+
+int add_channel_to_procdir(void)
+{
+       int i=0;
+
+       for (i=0; i < candevices_p[bc]->nr_82527_chips + 
+                       candevices_p[bc]->nr_sja1000_chips; i++) {
+
+               base->channel[cc] = (struct channelproc_t *)
+                       kmalloc(sizeof(struct channelproc_t), GFP_KERNEL);
+               if (base->channel[cc] == NULL)
+                       return -ENOMEM;
+               else if (add_mem_to_list(base->channel[cc]))
+                       return -ENOMEM;
+
+               sprintf(base->channel[cc]->ch_name, "channel%d",cc);
+                                               
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+               base->channel[cc]->ch_entry = new_can_proc_entry(0, 
+                                               base->channel[cc]->ch_name,
+                                               S_IFDIR | S_IRUGO | S_IXUGO, 0, 
+                                               base->can_proc_entry);
+#else
+               base->channel[cc]->ch_entry = create_proc_entry(
+                                               base->channel[cc]->ch_name,
+                                               S_IFDIR | S_IRUGO |S_IXUGO,
+                                               base->can_proc_entry);
+#endif
+               if (base->channel[cc]->ch_entry == NULL)
+                       return -ENODEV;
+
+               add_object_to_procdir();
+
+               cc++;
+       } 
+
+       return 0;
+}
+
+int remove_channel_from_procdir(void)
+{
+       
+       while (cc != 0) {
+               cc--;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+               if (can_remove_proc_entry(base->channel[cc]->ch_entry,
+                                                       base->can_proc_entry))
+                       return -ENODEV;
+#else
+               remove_proc_entry(base->channel[cc]->ch_name,
+                                                       base->can_proc_entry);
+#endif
+               if (remove_object_from_procdir())
+                       return -ENODEV; 
+       }
+
+       return 0;
+}
+
+
+int add_object_to_procdir(void)
+{
+       int i=0, obj=0;
+
+       if (!strcmp(chips_p[cc]->chip_type,"i82527"))
+               obj=15;
+       if (!strcmp(chips_p[cc]->chip_type,"sja1000"))
+               obj=1;
+
+       for (i=0; i<obj; i++) {
+               oc=i;
+               base->channel[cc]->object[i] = (struct objectproc_t *)
+                       kmalloc(sizeof(struct objectproc_t),GFP_KERNEL);
+                               
+                               
+               if (base->channel[cc]->object[i] == NULL)
+                       return -ENOMEM;
+               else if (add_mem_to_list( base->channel[cc]->object[i]))
+                       return -ENOMEM;
+
+               sprintf(base->channel[cc]->object[i]->obj_name,"object%d",i);
+               sprintf(base->channel[cc]->object[i]->lnk_name,"dev");
+                                                               
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+               base->channel[cc]->object[i]->obj_entry=new_can_proc_entry(
+                               0, base->channel[cc]->object[i]->obj_name,
+                               S_IFDIR | S_IRUGO | S_IXUGO, 0, 
+                               base->channel[cc]->ch_entry);
+               if (base->channel[cc]->object[i]->obj_entry == NULL)
+                       return -ENODEV;
+               base->channel[cc]->object[i]->lnk = new_can_proc_entry(
+                               0, base->channel[cc]->object[i]->lnk_name, 
+                               S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO,
+                               0, base->channel[cc]->object[i]->obj_entry);
+               if (base->channel[cc]->object[i]->lnk == NULL)
+                       return -ENODEV;
+               sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/can");
+               base->channel[cc]->object[i]->lnk->readlink_proc =
+                                                               candev_readlink;
+
+#else
+               base->channel[cc]->object[i]->obj_entry = create_proc_entry(
+                               base->channel[cc]->object[i]->obj_name,
+                               S_IFDIR | S_IRUGO | S_IXUGO,
+                               base->channel[cc]->ch_entry);
+               if (base->channel[cc]->object[i]->obj_entry == NULL)
+                       return -ENODEV;
+               sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/can%d",
+                       chips_p[cc]->msgobj[i]->minor);
+               base->channel[cc]->object[i]->lnk = proc_symlink(
+                               base->channel[cc]->object[i]->lnk_name,
+                               base->channel[cc]->object[i]->obj_entry,
+                               base->channel[cc]->object[i]->lnk_dev);
+               if (base->channel[cc]->object[i]->lnk == NULL)
+                       return -ENODEV;
+#endif
+
+       }
+       return 0;
+} 
+
+int remove_object_from_procdir(void)
+{
+       int i=0, obj=0;
+
+       if (!strcmp(chips_p[cc]->chip_type,"i82527"))
+               obj=15;
+       if (!strcmp(chips_p[cc]->chip_type,"sja1000"))
+               obj=1;
+
+       for (i=0; i<obj; i++) {
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+               if (can_remove_proc_entry( base->channel[cc]->object[i]->lnk,
+                               base->channel[cc]->object[i]->obj_entry))       
+                       return -ENODEV;
+               if (can_remove_proc_entry(
+                               base->channel[cc]->object[i]->obj_entry,
+                               base->channel[cc]->ch_entry))
+                       return -ENODEV;
+#else
+               remove_proc_entry(base->channel[cc]->object[i]->lnk_name,
+                               base->channel[cc]->object[i]->obj_entry);
+               remove_proc_entry(base->channel[cc]->object[i]->obj_name,
+                                       base->channel[cc]->ch_entry);
+#endif
+               
+       }
+       return 0;
+}
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+static int candev_readlink(struct proc_dir_entry *de, char *page)
+{
+       int i=0, nchip=0, nobj=0;
+       char chip[20], object[20], tmp[6];
+
+       sprintf(chip, de->parent->parent->name+7);
+       sprintf(object, de->parent->name+6);
+
+       for (i=0; i<MAX_TOT_CHIPS; i++) {
+               sprintf(tmp,"%d",i);
+               if (!strcmp(chip,tmp)) {
+                       nchip=i;
+                       break;
+               }       
+       }
+       for (i=0; i<MAX_MSGOBJS; i++) {
+               sprintf(tmp,"%d",i);
+               if (!strcmp(object,tmp)) {
+                       nobj=i;
+                       break;
+               }
+       }
+
+       return sprintf(page,"/dev/can%d",chips_p[nchip]->msgobj[nobj]->minor );
+}
+#endif //End of candev_readlink for kernel 2.2