]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/proc.c
Merge branch 'master' into can-usb1
[lincan.git] / lincan / src / proc.c
1 /**************************************************************************/
2 /* File: proc.c - proc filesystem entries for CAN driver                  */
3 /*                                                                        */
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>      */
9 /*                                                                        */
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.                                              */
20 /*                                                                        */
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:                                                     */
24 /*                                                                        */
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 /**************************************************************************/
34
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"
40
41 #define __NO_VERSION__
42 #include <linux/module.h>
43 #include <linux/mutex.h>
44
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);
50
51 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
52 static int can_proc_readlink(struct proc_dir_entry *ent, char *page);
53 #endif
54
55 #if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
56 #define CAN_PROC_ROOT (&proc_root)
57 #else /* >= 2.6.26 */
58 #define CAN_PROC_ROOT (NULL)
59 #endif /* >= 2.6.26 */
60
61 static int cc=0; /* static counter for each CAN chip */
62
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 */
66
67 /* The following functions are needed only for kernel version 2.2. Kernel
68  * version 2.4 already defines them for us.
69  */
70 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
71 static void can_fill_inode(struct inode *inode, int fill)
72 {
73         if (fill)
74                 MOD_INC_USE_COUNT;
75         else
76                 MOD_DEC_USE_COUNT;
77 }
78
79 static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
80                                         struct proc_dir_entry *parent)
81 {
82         struct proc_dir_entry *new_entry = NULL;
83         char *namestore;
84         int namelen;
85
86         if(!name || !parent)
87                 return NULL;
88         namelen=strlen(name);
89         if(!namelen)
90                 return NULL;
91
92         new_entry = (struct proc_dir_entry *)
93                         can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
94
95         if (new_entry == NULL)
96                 return NULL;
97
98         memset(new_entry, 0, sizeof(struct proc_dir_entry));
99
100         /* Store copy of the proc entry name */
101         namestore = ((char *) new_entry) + sizeof(struct proc_dir_entry);
102         memcpy(namestore, name, namelen + 1);
103
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;
111
112         proc_register(parent, new_entry);
113
114         return new_entry;
115 }
116
117 static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
118 {
119         if (del != NULL) {
120                 proc_unregister(parent, del->low_ino);
121                 can_checked_free(del);
122                 return 0;
123         }
124         else return -ENODEV;
125 }
126
127
128 static int can_proc_readlink(struct proc_dir_entry *ent, char *page)
129 {
130         char *link_dest = (char*)ent->data;
131
132         strcpy(page, link_dest);
133         return strlen(link_dest);
134 }
135
136
137
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)
141 {
142         struct proc_dir_entry *entry;
143
144
145         entry = can_create_proc_entry(name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, parent);
146         if (entry == NULL)
147                 return NULL;
148         entry->readlink_proc = can_proc_readlink;
149         entry->data = dest;
150         return entry;
151 }
152
153 #else /* Functions forwarded for kernel 2.4 and above */
154
155 static inline struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
156                                         struct proc_dir_entry *parent)
157 {
158         return create_proc_entry(name, mode, parent);
159 }
160
161
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)
165 {
166         if(!del) return -ENODEV;
167         remove_proc_entry(del->name,parent);
168         return 0;
169 }
170
171 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
172                 struct proc_dir_entry *parent, const char *dest)
173 {
174         return proc_symlink(name, parent, dest);
175 }
176
177 #endif /* Functions required for kernel 2.2 */
178
179 /* can_init_procdir registers the entire CAN directory tree recursively at
180  * the proc system.
181  */
182 int can_init_procdir(void)
183 {
184         int board;
185         struct candevice_t *candev;
186
187         mutex_init(&proc_mutex);
188
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)
192                 return -ENODEV;
193
194         for (board=0; board<hardware_p->nr_boards; board++) {
195                 candev=hardware_p->candevice[board];
196                 if(candev) add_channel_to_procdir(candev);
197         }
198
199         return 0;
200 }
201
202 /* can_init_procentry registers entry of a new board in CAN directory tree at
203  * the proc system.
204  */
205 int can_init_procentry(int board)
206 {
207         struct candevice_t *candev;
208         candev=hardware_p->candevice[board];
209         if(candev)
210                 return add_channel_to_procdir(candev);
211         return -ENODEV;
212 }
213
214 /* can_delete_procdir removes the entire CAN tree from the proc system */
215 int can_delete_procdir(void)
216 {
217         if (remove_channels_from_procdir())
218                 return -ENODEV;
219         /* name: "can" */
220         if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT))
221                 return -ENODEV;
222
223         return 0;
224 }
225
226 /* can_delete_procentry removes device entries from CAN tree in the proc system */
227 int can_delete_procentry(struct candevice_t *candev)
228 {
229         if (remove_channel_from_procdir(candev))
230                 return -ENODEV;
231
232         return 0;
233 }
234
235 static int can_chip_procinfo(char *buf, char **start, off_t offset,
236                  int count, int *eof, void *data)
237 {
238         struct canchip_t *chip=data;
239         int len=0;
240
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);
252
253
254 #if 0
255         /* Chip specific info if available */
256         if(chip->chipspecops->get_info)
257                 len += (chip->chipspecops->get_info)(chip,buf+len);
258 #endif
259
260         *eof = 1;
261         return len;
262 }
263
264
265 int add_channel_to_procdir(struct candevice_t *candev)
266 {
267         int i=0;
268
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;
273
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);
278                         return -ENOMEM;
279                 }
280
281                 sprintf(base->channel[i]->ch_name, "channel%d",i);
282
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);
287
288                 if (base->channel[i]->ch_entry == NULL){
289                         mutex_unlock(&proc_mutex);
290                         return -ENODEV;
291                 }
292
293                 add_object_to_procdir(i);
294
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 */
298                                        can_chip_procinfo,
299                                        chips_p[i]);
300                 cc++;
301         }
302         mutex_unlock(&proc_mutex);
303
304         return 0;
305 }
306
307 int remove_channels_from_procdir(void)
308 {
309         int i=0;
310
311         mutex_lock(&proc_mutex);
312         for (i=0; i < MAX_TOT_CHIPS; i++){
313                 if (!chips_p[i]) continue;
314
315                 cc--;
316
317                 if(!base->channel[i]) continue;
318
319                 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
320
321                 if (remove_object_from_procdir(i)){
322                         mutex_unlock(&proc_mutex);
323                         return -ENODEV;
324                 }
325
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);
330                         return -ENODEV;
331                 }
332
333                 can_checked_free(base->channel[i]);
334                 base->channel[i] = NULL;
335         }
336         mutex_unlock(&proc_mutex);
337
338         return 0;
339 }
340
341 int remove_channel_from_procdir(struct candevice_t *candev)
342 {
343         int i=0,j=0;
344
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;
350
351                 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
352
353                 if (remove_object_from_procdir(i)){
354                         mutex_unlock(&proc_mutex);
355                         return -ENODEV;
356                 }
357
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);
362                         return -ENODEV;
363                 }
364
365                 can_checked_free(base->channel[i]);
366                 base->channel[i] = NULL;
367
368                 cc--;
369         }
370         mutex_unlock(&proc_mutex);
371
372         return 0;
373 }
374
375
376 int add_object_to_procdir(int chip_nr)
377 {
378         int i, max_objects;
379
380         max_objects=chips_p[chip_nr]->max_objects;
381
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));
385
386                 if (base->channel[chip_nr]->object[i] == NULL)
387                         return -ENOMEM;
388
389                 sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
390                 sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
391
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)
397                         return -ENODEV;
398
399                 sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d",
400                         chips_p[chip_nr]->msgobj[i]->minor);
401
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)
407                         return -ENODEV;
408
409         }
410         return 0;
411 }
412
413 int remove_object_from_procdir(int chip_nr)
414 {
415         int i=0, obj=0;
416
417         obj=chips_p[chip_nr]->max_objects;
418
419         for (i=0; i<obj; i++) {
420                 if(!base->channel[chip_nr]->object[i]) continue;
421
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))
425                         return -ENODEV;
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))
430                         return -ENODEV;
431
432                 can_checked_free(base->channel[chip_nr]->object[i]);
433
434                 base->channel[chip_nr]->object[i]=NULL;
435         }
436         return 0;
437 }
438