X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/bb942b0bf58dd15491aee5acb3b4ec76559104a1..05dd2640c82d97d88f0bcab5344630f24212836b:/lincan/src/proc.c diff --git a/lincan/src/proc.c b/lincan/src/proc.c index 98fbb80..aaab028 100644 --- a/lincan/src/proc.c +++ b/lincan/src/proc.c @@ -1,11 +1,36 @@ -/* proc.c - * Linux CAN-bus device driver. - * Written by Arnaud Westenberg email:arnaud@wanadoo.nl - * 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.3 17 Jun 2004 - */ +/**************************************************************************/ +/* File: proc.c - proc filesystem entries for CAN driver */ +/* */ +/* LinCAN - (Not only) Linux CAN bus driver */ +/* Copyright (C) 2002-2009 DCE FEE CTU Prague */ +/* Copyright (C) 2002-2009 Pavel Pisa */ +/* Funded by OCERA and FRESCOR IST projects */ +/* Based on CAN driver code by Arnaud Westenberg */ +/* */ +/* 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" @@ -15,9 +40,11 @@ #define __NO_VERSION__ #include +#include 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); @@ -25,10 +52,17 @@ int remove_object_from_procdir(int chip_nr); static int can_proc_readlink(struct proc_dir_entry *ent, char *page); #endif +#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 */ + 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. @@ -48,14 +82,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) @@ -94,7 +128,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); } @@ -106,8 +140,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; @@ -149,32 +183,56 @@ int can_init_procdir(void) { int board; struct candevice_t *candev; - base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO | - S_IXUGO, &proc_root); + + 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; for (board=0; boardnr_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, &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; @@ -208,58 +266,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; } @@ -280,7 +388,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, @@ -300,7 +408,7 @@ int add_object_to_procdir(int chip_nr) } return 0; -} +} int remove_object_from_procdir(int chip_nr) { @@ -310,10 +418,10 @@ int remove_object_from_procdir(int chip_nr) for (i=0; ichannel[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(