]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/proc.c
Merge master into can-usb1 branch to include proc update for 3.12+ kernels.
[lincan.git] / lincan / src / proc.c
index 79309e0e35affbe900df17959b6da583c85438fe..b9d34192210e8b2ad94fad37bd74168f8f9c3b5c 100644 (file)
-/* 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
- */ 
+/**************************************************************************/
+/* File: proc.c - proc filesystem entries for CAN driver                  */
+/*                                                                        */
+/* LinCAN - (Not only) Linux CAN bus driver                               */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz>             */
+/* Funded by OCERA and FRESCOR IST projects                               */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
+/*                                                                        */
+/* LinCAN is free software; you can redistribute it and/or modify it      */
+/* under terms of the GNU General Public License as published by the      */
+/* Free Software Foundation; either version 2, or (at your option) any    */
+/* later version.  LinCAN is distributed in the hope that it will be      */
+/* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
+/* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
+/* General Public License for more details. You should have received a    */
+/* copy of the GNU General Public License along with LinCAN; see file     */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
+/* Cambridge, MA 02139, USA.                                              */
+/*                                                                        */
+/* To allow use of LinCAN in the compact embedded systems firmware        */
+/* and RT-executives (RTEMS for example), main authors agree with next    */
+/* special exception:                                                     */
+/*                                                                        */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce    */
+/* an application image/executable, does not by itself cause the          */
+/* resulting application image/executable to be covered by                */
+/* the GNU General Public License.                                        */
+/* This exception does not however invalidate any other reasons           */
+/* why the executable file might be covered by the GNU Public License.    */
+/* Publication of enhanced or derived LinCAN files is required although.  */
+/**************************************************************************/
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+#include "../include/proc.h"
+#include "../include/setup.h"
 
 #define __NO_VERSION__
 #include <linux/module.h>
+#include <linux/mutex.h>
 
-#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
+int add_channel_to_procdir(struct candevice_t *candev);
+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);
 
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
+static int can_proc_readlink(struct proc_dir_entry *ent, char *page);
 #endif
 
-#include <linux/version.h>
-#include <linux/kernel.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include <linux/malloc.h>
-#else
-#include <linux/slab.h>
-#endif
-#include <linux/proc_fs.h>
-#include <linux/version.h>
+#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
+#define CAN_PROC_ROOT (&proc_root)
+#else /* >= 2.6.26 */
+#define CAN_PROC_ROOT (NULL)
+#endif /* >= 2.6.26 */
 
-#include "../include/main.h"
-#include "../include/proc.h"
-#include "../include/setup.h"
+static int cc=0; /* static counter for each CAN chip */
 
-int add_channel_to_procdir(void);
-int remove_channel_from_procdir(void);
-int add_object_to_procdir(void);
-int remove_object_from_procdir(void);
+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 */
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-static int candev_readlink(struct proc_dir_entry *de, char *page);
-#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
 
-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 */
+#include <linux/seq_file.h>
 
-struct canproc_t can_proc_base;
-struct canproc_t *base=&can_proc_base;
+#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, \
+};
 
-/* 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))
+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)
@@ -59,23 +196,36 @@ static void can_fill_inode(struct inode *inode, int fill)
                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)
+static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
+                                       struct proc_dir_entry *parent)
 {
        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 *)
+                       can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
 
-       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;
+       /* Store copy of the proc entry name */
+       namestore = ((char *) new_entry) + sizeof(struct proc_dir_entry);
+       memcpy(namestore, name, namelen + 1);
+
+       new_entry->low_ino = 0;
+       new_entry->namelen = namelen;
+       new_entry->name = namestore;
        new_entry->mode = mode;
-       new_entry->nlink = nlink;
+       new_entry->nlink = 0;
        new_entry->fill_inode = can_fill_inode;
        new_entry->parent = parent;
 
@@ -84,228 +234,308 @@ static struct proc_dir_entry * new_can_proc_entry(unsigned short inode,
        return new_entry;
 }
 
-int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
+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 can_create_proc_entry(name, S_IFDIR | mode, parent);
+}
+
+static int can_proc_remove(struct proc_dir_entry *del)
 {
        if (del != NULL) {
-               proc_unregister(parent, del->low_ino);
-               kfree(del);
-               del = NULL;
+               proc_unregister(del->parent, del->low_ino);
+               can_checked_free(del);
                return 0;
        }
        else return -ENODEV;
 }
-#endif // Functions required for kernel 2.2
+
+
+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);
+}
+
+
+
+/* This compatibility version of proc_symlink does not store local copy of destination */
+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;
+       entry->readlink_proc = can_proc_readlink;
+       entry->data = dest;
+       return entry;
+}
+
+#endif /* Linux 2.2 - 2.3 kernels */
+
+#endif /* Linux kernel 3.6 and 3.10+ */
 
 /* 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,3,0))
-       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
+       int board;
+       struct candevice_t *candev;
+
+       mutex_init(&proc_mutex);
+
+       base->can_proc_entry = can_proc_mkdir_mode("can", S_IFDIR | S_IRUGO |
+                                       S_IXUGO, CAN_PROC_ROOT);
        if (base->can_proc_entry == NULL)
                return -ENODEV;
 
-       for (bc=0; bc<hardware_p->nr_boards; bc++) {
-               add_channel_to_procdir();
-       } 
+       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;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-       if (can_remove_proc_entry(base->can_proc_entry, &proc_root)) 
+       /* name: "can" */
+       if (can_proc_remove(base->can_proc_entry))
                return -ENODEV;
-#else
-       remove_proc_entry("can", &proc_root);
+
+       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_show(can_proc_seq_file_t *sqf, void *data)
+{
+       struct canchip_t *chip=can_seq_data(sqf);
+
+       /* Generic chip info */
+       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));
+       can_seq_printf(sqf, "config  : %s\n",
+                       (chip->flags & CHIP_CONFIGURED) ? "yes":"no");
+       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 */
+       if(chip->chipspecops->get_info)
+               len += (chip->chipspecops->get_info)(chip,buf+len);
 #endif
 
        return 0;
 }
 
-int add_channel_to_procdir(void)
+CAN_PROC_SHOW_SINGLE_OPS_DECLARE(can_chip_procinfo_ops, can_chip_procinfo_show);
+
+int add_channel_to_procdir(struct candevice_t *candev)
 {
        int i=0;
 
-       for (i=0; i < candevices_p[bc]->nr_82527_chips + 
-                       candevices_p[bc]->nr_sja1000_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 *)
-                       kmalloc(sizeof(struct channelproc_t), GFP_KERNEL);
-               if (base->channel[cc] == NULL)
-                       return -ENOMEM;
-               else if (add_mem_to_list(base->channel[cc]))
+               base->channel[i] = (struct channelproc_t *)
+                       can_checked_malloc(sizeof(struct channelproc_t));
+               if (base->channel[i] == NULL){
+                       mutex_unlock(&proc_mutex);
                        return -ENOMEM;
+               }
 
-               sprintf(base->channel[cc]->ch_name, "channel%d",cc);
-                                               
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-               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,
+               sprintf(base->channel[i]->ch_name, "channel%d",i);
+
+               base->channel[i]->ch_entry = can_proc_mkdir_mode(
+                                               base->channel[i]->ch_name,
                                                S_IFDIR | S_IRUGO |S_IXUGO,
                                                base->can_proc_entry);
-#endif
-               if (base->channel[cc]->ch_entry == NULL)
+
+               if (base->channel[i]->ch_entry == NULL){
+                       mutex_unlock(&proc_mutex);
                        return -ENODEV;
+               }
 
-               add_object_to_procdir();
+               add_object_to_procdir(i);
 
+               can_create_proc_read_entry("chip_info",        /* proc entry name */
+                                      0,                  /* protection mask, 0->default */
+                                      base->channel[i]->ch_entry,  /* parent dir, NULL->/proc */
+                                      &can_chip_procinfo_ops,
+                                      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 (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-               if (can_remove_proc_entry(base->channel[cc]->ch_entry,
-                                                       base->can_proc_entry))
+
+               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;
-#else
-               remove_proc_entry(base->channel[cc]->ch_name,
-                                                       base->can_proc_entry);
-#endif
-               if (remove_object_from_procdir())
-                       return -ENODEV; 
+               }
+
+               /* name: base->channel[cc]->ch_name */
+               if (can_proc_remove(base->channel[i]->ch_entry)){
+                       mutex_unlock(&proc_mutex);
+                       return -ENODEV;
+               }
+
+               can_checked_free(base->channel[i]);
+               base->channel[i] = NULL;
        }
+       mutex_unlock(&proc_mutex);
 
        return 0;
 }
 
-
-int add_object_to_procdir(void)
+int remove_channel_from_procdir(struct candevice_t *candev)
 {
-       int i=0, obj=0;
+       int i=0,j=0;
 
-       if (!strcmp(chips_p[cc]->chip_type,"i82527"))
-               obj=15;
-       if (!strcmp(chips_p[cc]->chip_type,"sja1000"))
-               obj=1;
+       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;
 
-       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;
+               remove_proc_entry("chip_info", base->channel[i]->ch_entry);
 
-               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,3,0))
-               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)
+               if (remove_object_from_procdir(i)){
+                       mutex_unlock(&proc_mutex);
                        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)
+               }
+
+               /* name: base->channel[cc]->ch_name */
+               if (can_proc_remove(base->channel[i]->ch_entry)){
+                       mutex_unlock(&proc_mutex);
                        return -ENODEV;
-               sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/can");
-               base->channel[cc]->object[i]->lnk->readlink_proc =
-                                                               candev_readlink;
+               }
+
+               can_checked_free(base->channel[i]);
+               base->channel[i] = NULL;
+
+               cc--;
+       }
+       mutex_unlock(&proc_mutex);
+
+       return 0;
+}
+
+
+int add_object_to_procdir(int chip_nr)
+{
+       int i, max_objects;
+
+       max_objects=chips_p[chip_nr]->max_objects;
 
-#else
-               base->channel[cc]->object[i]->obj_entry = create_proc_entry(
-                               base->channel[cc]->object[i]->obj_name,
+       for (i=0; i<max_objects; i++) {
+               base->channel[chip_nr]->object[i] = (struct objectproc_t *)
+                       can_checked_malloc(sizeof(struct objectproc_t));
+
+               if (base->channel[chip_nr]->object[i] == NULL)
+                       return -ENOMEM;
+
+               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_proc_mkdir_mode(
+                               base->channel[chip_nr]->object[i]->obj_name,
                                S_IFDIR | S_IRUGO | S_IXUGO,
-                               base->channel[cc]->ch_entry);
-               if (base->channel[cc]->object[i]->obj_entry == NULL)
+                               base->channel[chip_nr]->ch_entry);
+               if (base->channel[chip_nr]->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)
+
+               sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d",
+                       chips_p[chip_nr]->msgobj[i]->minor);
+
+               base->channel[chip_nr]->object[i]->lnk = can_proc_symlink(
+                               base->channel[chip_nr]->object[i]->lnk_name,
+                               base->channel[chip_nr]->object[i]->obj_entry,
+                               base->channel[chip_nr]->object[i]->lnk_dev);
+               if (base->channel[chip_nr]->object[i]->lnk == NULL)
                        return -ENODEV;
-#endif
 
        }
        return 0;
-} 
+}
 
-int remove_object_from_procdir(void)
+int remove_object_from_procdir(int chip_nr)
 {
        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;
+       obj=chips_p[chip_nr]->max_objects;
 
        for (i=0; i<obj; i++) {
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-               if (can_remove_proc_entry( base->channel[cc]->object[i]->lnk,
-                               base->channel[cc]->object[i]->obj_entry))       
+               if(!base->channel[chip_nr]->object[i]) continue;
+
+               /* name: base->channel[chip_nr]->object[i]->lnk_name */
+               if (can_proc_remove( base->channel[chip_nr]->object[i]->lnk))
                        return -ENODEV;
-               if (can_remove_proc_entry(
-                               base->channel[cc]->object[i]->obj_entry,
-                               base->channel[cc]->ch_entry))
+               /* name: base->channel[chip_nr]->object[i]->obj_name */
+               if (can_proc_remove(base->channel[chip_nr]->object[i]->obj_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
-               
+
+               can_checked_free(base->channel[chip_nr]->object[i]);
+
+               base->channel[chip_nr]->object[i]=NULL;
        }
        return 0;
 }
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-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