]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/proc.c
Merge branch 'master' into can-usb1
[lincan.git] / lincan / src / proc.c
index a85183091047a6d11aac40ee9b660da7cbb28583..e423b92725abca0012a166c2b1315554b03246fd 100644 (file)
@@ -5,7 +5,7 @@
  * email:pisa@cmp.felk.cvut.cz
  * This software is released under the GPL-License.
  * Version lincan-0.3  17 Jun 2004
- */ 
+ */
 
 #include "../include/can.h"
 #include "../include/can_sysdep.h"
 
 #define __NO_VERSION__
 #include <linux/module.h>
+#include <linux/mutex.h>
 
 int add_channel_to_procdir(struct candevice_t *candev);
-int remove_channel_from_procdir(void);
+int remove_channels_from_procdir(void);
+int remove_channel_from_procdir(struct candevice_t *candev);
 int add_object_to_procdir(int chip_nr);
 int remove_object_from_procdir(int chip_nr);
 
@@ -35,6 +37,7 @@ 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;
+DEFINE_MUTEX(proc_mutex);              /* synchronize access to canproc_t array */
 
 /* The following functions are needed only for kernel version 2.2. Kernel
  * version 2.4 already defines them for us.
@@ -54,14 +57,14 @@ static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mo
        struct proc_dir_entry *new_entry = NULL;
        char *namestore;
        int namelen;
-       
+
        if(!name || !parent)
                return NULL;
        namelen=strlen(name);
        if(!namelen)
                return NULL;
 
-       new_entry = (struct proc_dir_entry *) 
+       new_entry = (struct proc_dir_entry *)
                        can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
 
        if (new_entry == NULL)
@@ -100,7 +103,7 @@ static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_ent
 static int can_proc_readlink(struct proc_dir_entry *ent, char *page)
 {
        char *link_dest = (char*)ent->data;
-       
+
        strcpy(page, link_dest);
        return strlen(link_dest);
 }
@@ -112,8 +115,8 @@ static inline struct proc_dir_entry *can_proc_symlink(const char *name,
                 struct proc_dir_entry *parent, const char *dest)
 {
        struct proc_dir_entry *entry;
-       
-       
+
+
        entry = can_create_proc_entry(name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, parent);
        if (entry == NULL)
                return NULL;
@@ -155,7 +158,10 @@ int can_init_procdir(void)
 {
        int board;
        struct candevice_t *candev;
-       base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO | 
+
+       mutex_init(&proc_mutex);
+
+       base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO |
                                        S_IXUGO, CAN_PROC_ROOT);
        if (base->can_proc_entry == NULL)
                return -ENODEV;
@@ -163,24 +169,45 @@ int can_init_procdir(void)
        for (board=0; board<hardware_p->nr_boards; board++) {
                candev=hardware_p->candevice[board];
                if(candev) add_channel_to_procdir(candev);
-       } 
+       }
 
        return 0;
 }
 
+/* can_init_procentry registers entry of a new board in CAN directory tree at
+ * the proc system.
+ */
+int can_init_procentry(int board)
+{
+       struct candevice_t *candev;
+       candev=hardware_p->candevice[board];
+       if(candev)
+               return add_channel_to_procdir(candev);
+       return -ENODEV;
+}
+
 /* can_delete_procdir removes the entire CAN tree from the proc system */
 int can_delete_procdir(void)
 {
-       if (remove_channel_from_procdir()) 
+       if (remove_channels_from_procdir())
                return -ENODEV;
        /* name: "can" */
-       if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT)) 
+       if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT))
+               return -ENODEV;
+
+       return 0;
+}
+
+/* can_delete_procentry removes device entries from CAN tree in the proc system */
+int can_delete_procentry(struct candevice_t *candev)
+{
+       if (remove_channel_from_procdir(candev))
                return -ENODEV;
 
        return 0;
 }
 
-static int can_chip_procinfo(char *buf, char **start, off_t offset, 
+static int can_chip_procinfo(char *buf, char **start, off_t offset,
                 int count, int *eof, void *data)
 {
        struct canchip_t *chip=data;
@@ -214,58 +241,108 @@ int add_channel_to_procdir(struct candevice_t *candev)
 {
        int i=0;
 
-       for (i=0; i < candev->nr_all_chips; i++) {
+       mutex_lock(&proc_mutex);
+       for (i=0; i < MAX_TOT_CHIPS; i++){
+               if (!chips_p[i]) continue;
+               if (chips_p[i]->hostdevice != candev) continue;
 
-               base->channel[cc] = (struct channelproc_t *)
+               base->channel[i] = (struct channelproc_t *)
                        can_checked_malloc(sizeof(struct channelproc_t));
-               if (base->channel[cc] == NULL)
+               if (base->channel[i] == NULL){
+                       mutex_unlock(&proc_mutex);
                        return -ENOMEM;
+               }
 
-               sprintf(base->channel[cc]->ch_name, "channel%d",cc);
-                                               
-               base->channel[cc]->ch_entry = can_create_proc_entry(
-                                               base->channel[cc]->ch_name,
+               sprintf(base->channel[i]->ch_name, "channel%d",i);
+
+               base->channel[i]->ch_entry = can_create_proc_entry(
+                                               base->channel[i]->ch_name,
                                                S_IFDIR | S_IRUGO |S_IXUGO,
                                                base->can_proc_entry);
 
-               if (base->channel[cc]->ch_entry == NULL)
+               if (base->channel[i]->ch_entry == NULL){
+                       mutex_unlock(&proc_mutex);
                        return -ENODEV;
+               }
 
-               add_object_to_procdir(cc);
+               add_object_to_procdir(i);
 
                create_proc_read_entry("chip_info",        /* proc entry name */
                                       0,                  /* protection mask, 0->default */
-                                      base->channel[cc]->ch_entry,  /* parent dir, NULL->/proc */
+                                      base->channel[i]->ch_entry,  /* parent dir, NULL->/proc */
                                       can_chip_procinfo,
-                                      candev->chip[i]);
-
+                                      chips_p[i]);
                cc++;
-       } 
+       }
+       mutex_unlock(&proc_mutex);
 
        return 0;
 }
 
-int remove_channel_from_procdir(void)
+int remove_channels_from_procdir(void)
 {
-       
-       while (cc != 0) {
+       int i=0;
+
+       mutex_lock(&proc_mutex);
+       for (i=0; i < MAX_TOT_CHIPS; i++){
+               if (!chips_p[i]) continue;
+
                cc--;
-               
-               if(!base->channel[cc]) continue;
-
-               remove_proc_entry("chip_info", base->channel[cc]->ch_entry);
-               
-               if (remove_object_from_procdir(cc))
-                       return -ENODEV; 
-                       
+
+               if(!base->channel[i]) continue;
+
+               remove_proc_entry("chip_info", base->channel[i]->ch_entry);
+
+               if (remove_object_from_procdir(i)){
+                       mutex_unlock(&proc_mutex);
+                       return -ENODEV;
+               }
+
                /* name: base->channel[cc]->ch_name */
-               if (can_remove_proc_entry(base->channel[cc]->ch_entry,
-                                                       base->can_proc_entry))
+               if (can_remove_proc_entry(base->channel[i]->ch_entry,
+                                                       base->can_proc_entry)){
+                       mutex_unlock(&proc_mutex);
                        return -ENODEV;
-                       
-               can_checked_free(base->channel[cc]);
-               base->channel[cc] = NULL;
+               }
+
+               can_checked_free(base->channel[i]);
+               base->channel[i] = NULL;
        }
+       mutex_unlock(&proc_mutex);
+
+       return 0;
+}
+
+int remove_channel_from_procdir(struct candevice_t *candev)
+{
+       int i=0,j=0;
+
+       mutex_lock(&proc_mutex);
+       for (i=0; i < MAX_TOT_CHIPS; i++){
+               if (!chips_p[i]) continue;
+               if (chips_p[i]->hostdevice != candev) continue;
+               if (!base->channel[i]) continue;
+
+               remove_proc_entry("chip_info", base->channel[i]->ch_entry);
+
+               if (remove_object_from_procdir(i)){
+                       mutex_unlock(&proc_mutex);
+                       return -ENODEV;
+               }
+
+               /* name: base->channel[cc]->ch_name */
+               if (can_remove_proc_entry(base->channel[i]->ch_entry,
+                                                       base->can_proc_entry)){
+                       mutex_unlock(&proc_mutex);
+                       return -ENODEV;
+               }
+
+               can_checked_free(base->channel[i]);
+               base->channel[i] = NULL;
+
+               cc--;
+       }
+       mutex_unlock(&proc_mutex);
 
        return 0;
 }
@@ -286,7 +363,7 @@ int add_object_to_procdir(int chip_nr)
 
                sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
                sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
-                                                               
+
                base->channel[chip_nr]->object[i]->obj_entry = can_create_proc_entry(
                                base->channel[chip_nr]->object[i]->obj_name,
                                S_IFDIR | S_IRUGO | S_IXUGO,
@@ -306,7 +383,7 @@ int add_object_to_procdir(int chip_nr)
 
        }
        return 0;
-} 
+}
 
 int remove_object_from_procdir(int chip_nr)
 {
@@ -316,10 +393,10 @@ int remove_object_from_procdir(int chip_nr)
 
        for (i=0; i<obj; i++) {
                if(!base->channel[chip_nr]->object[i]) continue;
-               
+
                /* name: base->channel[chip_nr]->object[i]->lnk_name */
                if (can_remove_proc_entry( base->channel[chip_nr]->object[i]->lnk,
-                               base->channel[chip_nr]->object[i]->obj_entry))  
+                               base->channel[chip_nr]->object[i]->obj_entry))
                        return -ENODEV;
                /* name: base->channel[chip_nr]->object[i]->obj_name */
                if (can_remove_proc_entry(