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