* Rewritten for new CAN queues by Pavel Pisa - OCERA team member
* email:pisa@cmp.felk.cvut.cz
* This software is released under the GPL-License.
- * Version lincan-0.2 9 Jul 2003
+ * Version lincan-0.3 17 Jun 2004
*/
#include "../include/can.h"
int add_channel_to_procdir(struct candevice_t *candev);
int remove_channel_from_procdir(void);
int add_object_to_procdir(int chip_nr);
-int remove_object_from_procdir(void);
+int remove_object_from_procdir(int chip_nr);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
-static int candev_readlink(struct proc_dir_entry *de, char *page);
+static int can_proc_readlink(struct proc_dir_entry *ent, char *page);
#endif
static int cc=0; /* static counter for each CAN chip */
-struct canproc_t can_proc_base;
-struct canproc_t *base=&can_proc_base;
+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.
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));
+ can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
+
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;
return new_entry;
}
-int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
+static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
{
if (del != NULL) {
proc_unregister(parent, del->low_ino);
}
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;
+}
+
+#else /* Functions forwarded for kernel 2.4 and above */
+
+static inline struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
+ struct proc_dir_entry *parent)
+{
+ return create_proc_entry(name, 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_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
+{
+ if(!del) return -ENODEV;
+ remove_proc_entry(del->name,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);
+}
+
+#endif /* Functions required for kernel 2.2 */
/* can_init_procdir registers the entire CAN directory tree recursively at
* the proc system.
{
int board;
struct candevice_t *candev;
-#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 |
+ base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO |
S_IXUGO, &proc_root);
-#endif
if (base->can_proc_entry == NULL)
return -ENODEV;
{
if (remove_channel_from_procdir())
return -ENODEV;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
+ /* name: "can" */
if (can_remove_proc_entry(base->can_proc_entry, &proc_root))
return -ENODEV;
-#else
- remove_proc_entry("can", &proc_root);
-#endif
return 0;
}
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_entry = can_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;
while (cc != 0) {
cc--;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
+
+ if(!base->channel[cc]) continue;
+
+ if (remove_object_from_procdir(cc))
+ return -ENODEV;
+
+ /* name: base->channel[cc]->ch_name */
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;
+
+ can_checked_free(base->channel[cc]);
+ base->channel[cc] = NULL;
}
return 0;
sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
- base->channel[chip_nr]->object[i]->obj_entry=new_can_proc_entry(
- 0, base->channel[chip_nr]->object[i]->obj_name,
- S_IFDIR | S_IRUGO | S_IXUGO, 0,
- base->channel[chip_nr]->ch_entry);
- if (base->channel[chip_nr]->object[i]->obj_entry == NULL)
- return -ENODEV;
- base->channel[chip_nr]->object[i]->lnk = new_can_proc_entry(
- 0, base->channel[chip_nr]->object[i]->lnk_name,
- S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO,
- 0, base->channel[chip_nr]->object[i]->obj_entry);
- if (base->channel[chip_nr]->object[i]->lnk == NULL)
- return -ENODEV;
- sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can");
- base->channel[chip_nr]->object[i]->lnk->readlink_proc =
- candev_readlink;
-
-#else
- base->channel[chip_nr]->object[i]->obj_entry = create_proc_entry(
+ 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,
base->channel[chip_nr]->ch_entry);
if (base->channel[chip_nr]->object[i]->obj_entry == NULL)
return -ENODEV;
+
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 = proc_symlink(
+
+ 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;
- obj=chips_p[cc]->max_objects;
+ 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_remove_proc_entry( base->channel[chip_nr]->object[i]->lnk,
+ base->channel[chip_nr]->object[i]->obj_entry))
return -ENODEV;
+ /* name: base->channel[chip_nr]->object[i]->obj_name */
if (can_remove_proc_entry(
- base->channel[cc]->object[i]->obj_entry,
- base->channel[cc]->ch_entry))
+ base->channel[chip_nr]->object[i]->obj_entry,
+ base->channel[chip_nr]->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
-
+
+ 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