]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/proc.c
Merge master into can-usb1 branch to include proc update for 3.12+ kernels.
[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 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
68
69 #include <linux/seq_file.h>
70
71 #define CAN_PROC_SHOW_SINGLE_OPS_DECLARE(ops_name, show_function) \
72 static int ops_name##_open(struct inode *inode, struct file *file) \
73 { \
74         return single_open(file, show_function, PDE_DATA(inode)); \
75 } \
76 static const struct file_operations ops_name = { \
77         .owner          = THIS_MODULE, \
78         .open           = ops_name##_open, \
79         .read           = seq_read, \
80         .llseek         = seq_lseek, \
81         .release        = single_release, \
82 };
83
84 typedef struct file_operations can_proc_read_entry_ops_t;
85 typedef struct seq_file can_proc_seq_file_t;
86
87 static inline void *can_seq_data(can_proc_seq_file_t *sqf)
88 {
89         return sqf->private;
90 }
91
92 #define can_seq_printf seq_printf
93
94 struct proc_dir_entry *can_create_proc_read_entry(const char *name,
95         mode_t mode, struct proc_dir_entry *parent,
96         const can_proc_read_entry_ops_t *proc_read_entry_ops, void * data)
97 {
98         return proc_create_data(name, mode, parent, proc_read_entry_ops, data);
99 }
100
101 struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode,
102                                        struct proc_dir_entry *parent)
103 {
104         return proc_mkdir_mode(name, mode, parent);
105 }
106
107 static int can_proc_remove(struct proc_dir_entry *del)
108 {
109         if(!del) return -ENODEV;
110         proc_remove(del);
111         return 0;
112 }
113
114 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
115                 struct proc_dir_entry *parent, const char *dest)
116 {
117         return proc_symlink(name, parent, dest);
118 }
119
120 #else /* kernel older than 3.10 */
121
122 typedef read_proc_t *can_proc_read_entry_ops_t;
123 typedef struct {
124         int len;
125         int limit;
126         char *buf;
127         void *private;
128 } can_proc_seq_file_t;
129
130 #define CAN_PROC_SHOW_SINGLE_OPS_DECLARE(ops_name, show_function) \
131 static int ops_name##_show_wrapper(char *buf, char **start, off_t offset, \
132                  int count, int *eof, void *data) \
133 { \
134         can_proc_seq_file_t seq_pos = { .len = 0, .buf = buf, .limit = PAGE_SIZE, \
135                                         .private = data}; \
136         *eof = 1; \
137         show_function(&seq_pos, data); \
138         return seq_pos.len; \
139 } \
140 const static can_proc_read_entry_ops_t ops_name = ops_name##_show_wrapper;
141
142 static inline void *can_seq_data(can_proc_seq_file_t *sqf)
143 {
144         return sqf->private;
145 }
146
147 static inline int can_seq_printf(can_proc_seq_file_t *sqf, const char *f, ...)
148 {
149         int ret;
150         va_list args;
151         va_start(args, f);
152         ret = vsnprintf(sqf->buf + sqf->len, sqf->limit - sqf->len, f, args);
153         sqf->len += ret;
154         if (sqf->len > sqf->limit)
155                 sqf->len = sqf->limit;
156         va_end(args);
157         return ret;
158 }
159
160 struct proc_dir_entry *can_create_proc_read_entry(const char *name,
161         mode_t mode, struct proc_dir_entry *parent,
162         const can_proc_read_entry_ops_t *proc_read_entry_ops, void * data)
163 {
164         return create_proc_read_entry(name, mode, parent, *proc_read_entry_ops, data);
165 }
166
167 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0))
168
169 struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode,
170                                        struct proc_dir_entry *parent)
171 {
172         return create_proc_entry(name, S_IFDIR | mode, parent);
173 }
174
175 /* This does not fully follow linux 2.4 and 2.6 prototype to simplify 2.2.x compatibility */
176 /* The newer kernels use entry name instead of pointer to the entry */
177 static int can_proc_remove(struct proc_dir_entry *del)
178 {
179         if(!del) return -ENODEV;
180         remove_proc_entry(del->name, del->parent);
181         return 0;
182 }
183
184 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
185                 struct proc_dir_entry *parent, const char *dest)
186 {
187         return proc_symlink(name, parent, dest);
188 }
189
190 #else /* ancient Linux kernel older than 2.3.0 */
191 static void can_fill_inode(struct inode *inode, int fill)
192 {
193         if (fill)
194                 MOD_INC_USE_COUNT;
195         else
196                 MOD_DEC_USE_COUNT;
197 }
198
199 static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
200                                         struct proc_dir_entry *parent)
201 {
202         struct proc_dir_entry *new_entry = NULL;
203         char *namestore;
204         int namelen;
205
206         if(!name || !parent)
207                 return NULL;
208         namelen=strlen(name);
209         if(!namelen)
210                 return NULL;
211
212         new_entry = (struct proc_dir_entry *)
213                         can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
214
215         if (new_entry == NULL)
216                 return NULL;
217
218         memset(new_entry, 0, sizeof(struct proc_dir_entry));
219
220         /* Store copy of the proc entry name */
221         namestore = ((char *) new_entry) + sizeof(struct proc_dir_entry);
222         memcpy(namestore, name, namelen + 1);
223
224         new_entry->low_ino = 0;
225         new_entry->namelen = namelen;
226         new_entry->name = namestore;
227         new_entry->mode = mode;
228         new_entry->nlink = 0;
229         new_entry->fill_inode = can_fill_inode;
230         new_entry->parent = parent;
231
232         proc_register(parent, new_entry);
233
234         return new_entry;
235 }
236
237 struct proc_dir_entry *can_create_proc_read_entry(const char *name,
238         mode_t mode, struct proc_dir_entry *parent,
239         read_proc_t *read_proc, void * data)
240 {
241         return create_proc_read_entry(name, mode, parent, read_proc, data);
242 }
243
244 struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode,
245                                        struct proc_dir_entry *parent)
246 {
247         return can_create_proc_entry(name, S_IFDIR | mode, parent);
248 }
249
250 static int can_proc_remove(struct proc_dir_entry *del)
251 {
252         if (del != NULL) {
253                 proc_unregister(del->parent, del->low_ino);
254                 can_checked_free(del);
255                 return 0;
256         }
257         else return -ENODEV;
258 }
259
260
261 static int can_proc_readlink(struct proc_dir_entry *ent, char *page)
262 {
263         char *link_dest = (char*)ent->data;
264
265         strcpy(page, link_dest);
266         return strlen(link_dest);
267 }
268
269
270
271 /* This compatibility version of proc_symlink does not store local copy of destination */
272 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
273                 struct proc_dir_entry *parent, const char *dest)
274 {
275         struct proc_dir_entry *entry;
276
277
278         entry = can_create_proc_entry(name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, parent);
279         if (entry == NULL)
280                 return NULL;
281         entry->readlink_proc = can_proc_readlink;
282         entry->data = dest;
283         return entry;
284 }
285
286 #endif /* Linux 2.2 - 2.3 kernels */
287
288 #endif /* Linux kernel 3.6 and 3.10+ */
289
290 /* can_init_procdir registers the entire CAN directory tree recursively at
291  * the proc system.
292  */
293 int can_init_procdir(void)
294 {
295         int board;
296         struct candevice_t *candev;
297
298         mutex_init(&proc_mutex);
299
300         base->can_proc_entry = can_proc_mkdir_mode("can", S_IFDIR | S_IRUGO |
301                                         S_IXUGO, CAN_PROC_ROOT);
302         if (base->can_proc_entry == NULL)
303                 return -ENODEV;
304
305         for (board=0; board<hardware_p->nr_boards; board++) {
306                 candev=hardware_p->candevice[board];
307                 if(candev) add_channel_to_procdir(candev);
308         }
309
310         return 0;
311 }
312
313 /* can_init_procentry registers entry of a new board in CAN directory tree at
314  * the proc system.
315  */
316 int can_init_procentry(int board)
317 {
318         struct candevice_t *candev;
319         candev=hardware_p->candevice[board];
320         if(candev)
321                 return add_channel_to_procdir(candev);
322         return -ENODEV;
323 }
324
325 /* can_delete_procdir removes the entire CAN tree from the proc system */
326 int can_delete_procdir(void)
327 {
328         if (remove_channels_from_procdir())
329                 return -ENODEV;
330         /* name: "can" */
331         if (can_proc_remove(base->can_proc_entry))
332                 return -ENODEV;
333
334         return 0;
335 }
336
337 /* can_delete_procentry removes device entries from CAN tree in the proc system */
338 int can_delete_procentry(struct candevice_t *candev)
339 {
340         if (remove_channel_from_procdir(candev))
341                 return -ENODEV;
342
343         return 0;
344 }
345
346 static int can_chip_procinfo_show(can_proc_seq_file_t *sqf, void *data)
347 {
348         struct canchip_t *chip=can_seq_data(sqf);
349
350         /* Generic chip info */
351         can_seq_printf(sqf, "type    : %s\n",chip->chip_type);
352         can_seq_printf(sqf, "index   : %d\n",chip->chip_idx);
353         can_seq_printf(sqf, "irq     : %d\n",chip->chip_irq);
354         can_seq_printf(sqf, "addr    : %lu\n",
355                         can_ioptr2ulong(chip->chip_base_addr));
356         can_seq_printf(sqf, "config  : %s\n",
357                         (chip->flags & CHIP_CONFIGURED) ? "yes":"no");
358         can_seq_printf(sqf, "clock   : %ld Hz\n",chip->clock);
359         can_seq_printf(sqf, "baud    : %ld\n",chip->baudrate);
360         can_seq_printf(sqf, "num obj : %d\n",chip->max_objects);
361
362 #if 0
363         /* Chip specific info if available */
364         if(chip->chipspecops->get_info)
365                 len += (chip->chipspecops->get_info)(chip,buf+len);
366 #endif
367
368         return 0;
369 }
370
371 CAN_PROC_SHOW_SINGLE_OPS_DECLARE(can_chip_procinfo_ops, can_chip_procinfo_show);
372
373 int add_channel_to_procdir(struct candevice_t *candev)
374 {
375         int i=0;
376
377         mutex_lock(&proc_mutex);
378         for (i=0; i < MAX_TOT_CHIPS; i++){
379                 if (!chips_p[i]) continue;
380                 if (chips_p[i]->hostdevice != candev) continue;
381
382                 base->channel[i] = (struct channelproc_t *)
383                         can_checked_malloc(sizeof(struct channelproc_t));
384                 if (base->channel[i] == NULL){
385                         mutex_unlock(&proc_mutex);
386                         return -ENOMEM;
387                 }
388
389                 sprintf(base->channel[i]->ch_name, "channel%d",i);
390
391                 base->channel[i]->ch_entry = can_proc_mkdir_mode(
392                                                 base->channel[i]->ch_name,
393                                                 S_IFDIR | S_IRUGO |S_IXUGO,
394                                                 base->can_proc_entry);
395
396                 if (base->channel[i]->ch_entry == NULL){
397                         mutex_unlock(&proc_mutex);
398                         return -ENODEV;
399                 }
400
401                 add_object_to_procdir(i);
402
403                 can_create_proc_read_entry("chip_info",        /* proc entry name */
404                                        0,                  /* protection mask, 0->default */
405                                        base->channel[i]->ch_entry,  /* parent dir, NULL->/proc */
406                                        &can_chip_procinfo_ops,
407                                        chips_p[i]);
408                 cc++;
409         }
410         mutex_unlock(&proc_mutex);
411
412         return 0;
413 }
414
415 int remove_channels_from_procdir(void)
416 {
417         int i=0;
418
419         mutex_lock(&proc_mutex);
420         for (i=0; i < MAX_TOT_CHIPS; i++){
421                 if (!chips_p[i]) continue;
422
423                 cc--;
424
425                 if(!base->channel[i]) continue;
426
427                 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
428
429                 if (remove_object_from_procdir(i)){
430                         mutex_unlock(&proc_mutex);
431                         return -ENODEV;
432                 }
433
434                 /* name: base->channel[cc]->ch_name */
435                 if (can_proc_remove(base->channel[i]->ch_entry)){
436                         mutex_unlock(&proc_mutex);
437                         return -ENODEV;
438                 }
439
440                 can_checked_free(base->channel[i]);
441                 base->channel[i] = NULL;
442         }
443         mutex_unlock(&proc_mutex);
444
445         return 0;
446 }
447
448 int remove_channel_from_procdir(struct candevice_t *candev)
449 {
450         int i=0,j=0;
451
452         mutex_lock(&proc_mutex);
453         for (i=0; i < MAX_TOT_CHIPS; i++){
454                 if (!chips_p[i]) continue;
455                 if (chips_p[i]->hostdevice != candev) continue;
456                 if (!base->channel[i]) continue;
457
458                 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
459
460                 if (remove_object_from_procdir(i)){
461                         mutex_unlock(&proc_mutex);
462                         return -ENODEV;
463                 }
464
465                 /* name: base->channel[cc]->ch_name */
466                 if (can_proc_remove(base->channel[i]->ch_entry)){
467                         mutex_unlock(&proc_mutex);
468                         return -ENODEV;
469                 }
470
471                 can_checked_free(base->channel[i]);
472                 base->channel[i] = NULL;
473
474                 cc--;
475         }
476         mutex_unlock(&proc_mutex);
477
478         return 0;
479 }
480
481
482 int add_object_to_procdir(int chip_nr)
483 {
484         int i, max_objects;
485
486         max_objects=chips_p[chip_nr]->max_objects;
487
488         for (i=0; i<max_objects; i++) {
489                 base->channel[chip_nr]->object[i] = (struct objectproc_t *)
490                         can_checked_malloc(sizeof(struct objectproc_t));
491
492                 if (base->channel[chip_nr]->object[i] == NULL)
493                         return -ENOMEM;
494
495                 sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
496                 sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
497
498                 base->channel[chip_nr]->object[i]->obj_entry = can_proc_mkdir_mode(
499                                 base->channel[chip_nr]->object[i]->obj_name,
500                                 S_IFDIR | S_IRUGO | S_IXUGO,
501                                 base->channel[chip_nr]->ch_entry);
502                 if (base->channel[chip_nr]->object[i]->obj_entry == NULL)
503                         return -ENODEV;
504
505                 sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d",
506                         chips_p[chip_nr]->msgobj[i]->minor);
507
508                 base->channel[chip_nr]->object[i]->lnk = can_proc_symlink(
509                                 base->channel[chip_nr]->object[i]->lnk_name,
510                                 base->channel[chip_nr]->object[i]->obj_entry,
511                                 base->channel[chip_nr]->object[i]->lnk_dev);
512                 if (base->channel[chip_nr]->object[i]->lnk == NULL)
513                         return -ENODEV;
514
515         }
516         return 0;
517 }
518
519 int remove_object_from_procdir(int chip_nr)
520 {
521         int i=0, obj=0;
522
523         obj=chips_p[chip_nr]->max_objects;
524
525         for (i=0; i<obj; i++) {
526                 if(!base->channel[chip_nr]->object[i]) continue;
527
528                 /* name: base->channel[chip_nr]->object[i]->lnk_name */
529                 if (can_proc_remove( base->channel[chip_nr]->object[i]->lnk))
530                         return -ENODEV;
531                 /* name: base->channel[chip_nr]->object[i]->obj_name */
532                 if (can_proc_remove(base->channel[chip_nr]->object[i]->obj_entry))
533                         return -ENODEV;
534
535                 can_checked_free(base->channel[chip_nr]->object[i]);
536
537                 base->channel[chip_nr]->object[i]=NULL;
538         }
539         return 0;
540 }
541