1 /**************************************************************************/
2 /* File: proc.c - proc filesystem entries for CAN driver */
4 /* LinCAN - (Not only) Linux CAN bus driver */
5 /* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
6 /* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
7 /* Funded by OCERA and FRESCOR IST projects */
8 /* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl> */
10 /* LinCAN is free software; you can redistribute it and/or modify it */
11 /* under terms of the GNU General Public License as published by the */
12 /* Free Software Foundation; either version 2, or (at your option) any */
13 /* later version. LinCAN is distributed in the hope that it will be */
14 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
15 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
16 /* General Public License for more details. You should have received a */
17 /* copy of the GNU General Public License along with LinCAN; see file */
18 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
19 /* Cambridge, MA 02139, USA. */
21 /* To allow use of LinCAN in the compact embedded systems firmware */
22 /* and RT-executives (RTEMS for example), main authors agree with next */
23 /* special exception: */
25 /* Including LinCAN header files in a file, instantiating LinCAN generics */
26 /* or templates, or linking other files with LinCAN objects to produce */
27 /* an application image/executable, does not by itself cause the */
28 /* resulting application image/executable to be covered by */
29 /* the GNU General Public License. */
30 /* This exception does not however invalidate any other reasons */
31 /* why the executable file might be covered by the GNU Public License. */
32 /* Publication of enhanced or derived LinCAN files is required although. */
33 /**************************************************************************/
35 #include "../include/can.h"
36 #include "../include/can_sysdep.h"
37 #include "../include/main.h"
38 #include "../include/proc.h"
39 #include "../include/setup.h"
41 #define __NO_VERSION__
42 #include <linux/module.h>
43 #include <linux/mutex.h>
45 int add_channel_to_procdir(struct candevice_t *candev);
46 int remove_channels_from_procdir(void);
47 int remove_channel_from_procdir(struct candevice_t *candev);
48 int add_object_to_procdir(int chip_nr);
49 int remove_object_from_procdir(int chip_nr);
51 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
52 static int can_proc_readlink(struct proc_dir_entry *ent, char *page);
55 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
56 #define CAN_PROC_ROOT (&proc_root)
58 #define CAN_PROC_ROOT (NULL)
59 #endif /* >= 2.6.26 */
61 static int cc=0; /* static counter for each CAN chip */
63 static struct canproc_t can_proc_base;
64 static struct canproc_t *base=&can_proc_base;
65 DEFINE_MUTEX(proc_mutex); /* synchronize access to canproc_t array */
67 /* The following functions are needed only for kernel version 2.2. Kernel
68 * version 2.4 already defines them for us.
70 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
71 static void can_fill_inode(struct inode *inode, int fill)
79 static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
80 struct proc_dir_entry *parent)
82 struct proc_dir_entry *new_entry = NULL;
92 new_entry = (struct proc_dir_entry *)
93 can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
95 if (new_entry == NULL)
98 memset(new_entry, 0, sizeof(struct proc_dir_entry));
100 /* Store copy of the proc entry name */
101 namestore = ((char *) new_entry) + sizeof(struct proc_dir_entry);
102 memcpy(namestore, name, namelen + 1);
104 new_entry->low_ino = 0;
105 new_entry->namelen = namelen;
106 new_entry->name = namestore;
107 new_entry->mode = mode;
108 new_entry->nlink = 0;
109 new_entry->fill_inode = can_fill_inode;
110 new_entry->parent = parent;
112 proc_register(parent, new_entry);
117 static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
120 proc_unregister(parent, del->low_ino);
121 can_checked_free(del);
128 static int can_proc_readlink(struct proc_dir_entry *ent, char *page)
130 char *link_dest = (char*)ent->data;
132 strcpy(page, link_dest);
133 return strlen(link_dest);
138 /* This compatibility version of proc_symlink does not store local copy of destination */
139 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
140 struct proc_dir_entry *parent, const char *dest)
142 struct proc_dir_entry *entry;
145 entry = can_create_proc_entry(name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, parent);
148 entry->readlink_proc = can_proc_readlink;
153 #else /* Functions forwarded for kernel 2.4 and above */
155 static inline struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
156 struct proc_dir_entry *parent)
158 return create_proc_entry(name, mode, parent);
162 /* This does not fully follow linux 2.4 and 2.6 prototype to simplify 2.2.x compatibility */
163 /* The newer kernels use entry name instead of pointer to the entry */
164 static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
166 if(!del) return -ENODEV;
167 remove_proc_entry(del->name,parent);
171 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
172 struct proc_dir_entry *parent, const char *dest)
174 return proc_symlink(name, parent, dest);
177 #endif /* Functions required for kernel 2.2 */
179 /* can_init_procdir registers the entire CAN directory tree recursively at
182 int can_init_procdir(void)
185 struct candevice_t *candev;
187 mutex_init(&proc_mutex);
189 base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO |
190 S_IXUGO, CAN_PROC_ROOT);
191 if (base->can_proc_entry == NULL)
194 for (board=0; board<hardware_p->nr_boards; board++) {
195 candev=hardware_p->candevice[board];
196 if(candev) add_channel_to_procdir(candev);
202 /* can_init_procentry registers entry of a new board in CAN directory tree at
205 int can_init_procentry(int board)
207 struct candevice_t *candev;
208 candev=hardware_p->candevice[board];
210 return add_channel_to_procdir(candev);
214 /* can_delete_procdir removes the entire CAN tree from the proc system */
215 int can_delete_procdir(void)
217 if (remove_channels_from_procdir())
220 if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT))
226 /* can_delete_procentry removes device entries from CAN tree in the proc system */
227 int can_delete_procentry(struct candevice_t *candev)
229 if (remove_channel_from_procdir(candev))
235 static int can_chip_procinfo(char *buf, char **start, off_t offset,
236 int count, int *eof, void *data)
238 struct canchip_t *chip=data;
241 /* Generic chip info */
242 len += sprintf(buf+len,"type : %s\n",chip->chip_type);
243 len += sprintf(buf+len,"index : %d\n",chip->chip_idx);
244 len += sprintf(buf+len,"irq : %d\n",chip->chip_irq);
245 len += sprintf(buf+len,"addr : %lu\n",
246 can_ioptr2ulong(chip->chip_base_addr));
247 len += sprintf(buf+len,"config : %s\n",
248 (chip->flags & CHIP_CONFIGURED) ? "yes":"no");
249 len += sprintf(buf+len,"clock : %ld Hz\n",chip->clock);
250 len += sprintf(buf+len,"baud : %ld\n",chip->baudrate);
251 len += sprintf(buf+len,"num obj : %d\n",chip->max_objects);
255 /* Chip specific info if available */
256 if(chip->chipspecops->get_info)
257 len += (chip->chipspecops->get_info)(chip,buf+len);
265 int add_channel_to_procdir(struct candevice_t *candev)
269 mutex_lock(&proc_mutex);
270 for (i=0; i < MAX_TOT_CHIPS; i++){
271 if (!chips_p[i]) continue;
272 if (chips_p[i]->hostdevice != candev) continue;
274 base->channel[i] = (struct channelproc_t *)
275 can_checked_malloc(sizeof(struct channelproc_t));
276 if (base->channel[i] == NULL){
277 mutex_unlock(&proc_mutex);
281 sprintf(base->channel[i]->ch_name, "channel%d",i);
283 base->channel[i]->ch_entry = can_create_proc_entry(
284 base->channel[i]->ch_name,
285 S_IFDIR | S_IRUGO |S_IXUGO,
286 base->can_proc_entry);
288 if (base->channel[i]->ch_entry == NULL){
289 mutex_unlock(&proc_mutex);
293 add_object_to_procdir(i);
295 create_proc_read_entry("chip_info", /* proc entry name */
296 0, /* protection mask, 0->default */
297 base->channel[i]->ch_entry, /* parent dir, NULL->/proc */
302 mutex_unlock(&proc_mutex);
307 int remove_channels_from_procdir(void)
311 mutex_lock(&proc_mutex);
312 for (i=0; i < MAX_TOT_CHIPS; i++){
313 if (!chips_p[i]) continue;
317 if(!base->channel[i]) continue;
319 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
321 if (remove_object_from_procdir(i)){
322 mutex_unlock(&proc_mutex);
326 /* name: base->channel[cc]->ch_name */
327 if (can_remove_proc_entry(base->channel[i]->ch_entry,
328 base->can_proc_entry)){
329 mutex_unlock(&proc_mutex);
333 can_checked_free(base->channel[i]);
334 base->channel[i] = NULL;
336 mutex_unlock(&proc_mutex);
341 int remove_channel_from_procdir(struct candevice_t *candev)
345 mutex_lock(&proc_mutex);
346 for (i=0; i < MAX_TOT_CHIPS; i++){
347 if (!chips_p[i]) continue;
348 if (chips_p[i]->hostdevice != candev) continue;
349 if (!base->channel[i]) continue;
351 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
353 if (remove_object_from_procdir(i)){
354 mutex_unlock(&proc_mutex);
358 /* name: base->channel[cc]->ch_name */
359 if (can_remove_proc_entry(base->channel[i]->ch_entry,
360 base->can_proc_entry)){
361 mutex_unlock(&proc_mutex);
365 can_checked_free(base->channel[i]);
366 base->channel[i] = NULL;
370 mutex_unlock(&proc_mutex);
376 int add_object_to_procdir(int chip_nr)
380 max_objects=chips_p[chip_nr]->max_objects;
382 for (i=0; i<max_objects; i++) {
383 base->channel[chip_nr]->object[i] = (struct objectproc_t *)
384 can_checked_malloc(sizeof(struct objectproc_t));
386 if (base->channel[chip_nr]->object[i] == NULL)
389 sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
390 sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
392 base->channel[chip_nr]->object[i]->obj_entry = can_create_proc_entry(
393 base->channel[chip_nr]->object[i]->obj_name,
394 S_IFDIR | S_IRUGO | S_IXUGO,
395 base->channel[chip_nr]->ch_entry);
396 if (base->channel[chip_nr]->object[i]->obj_entry == NULL)
399 sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d",
400 chips_p[chip_nr]->msgobj[i]->minor);
402 base->channel[chip_nr]->object[i]->lnk = can_proc_symlink(
403 base->channel[chip_nr]->object[i]->lnk_name,
404 base->channel[chip_nr]->object[i]->obj_entry,
405 base->channel[chip_nr]->object[i]->lnk_dev);
406 if (base->channel[chip_nr]->object[i]->lnk == NULL)
413 int remove_object_from_procdir(int chip_nr)
417 obj=chips_p[chip_nr]->max_objects;
419 for (i=0; i<obj; i++) {
420 if(!base->channel[chip_nr]->object[i]) continue;
422 /* name: base->channel[chip_nr]->object[i]->lnk_name */
423 if (can_remove_proc_entry( base->channel[chip_nr]->object[i]->lnk,
424 base->channel[chip_nr]->object[i]->obj_entry))
426 /* name: base->channel[chip_nr]->object[i]->obj_name */
427 if (can_remove_proc_entry(
428 base->channel[chip_nr]->object[i]->obj_entry,
429 base->channel[chip_nr]->ch_entry))
432 can_checked_free(base->channel[chip_nr]->object[i]);
434 base->channel[chip_nr]->object[i]=NULL;