]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/proc.c
98fbb80716f576d397094a354130410efc847482
[lincan.git] / lincan / src / proc.c
1 /* proc.c
2  * Linux CAN-bus device driver.
3  * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
4  * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
5  * email:pisa@cmp.felk.cvut.cz
6  * This software is released under the GPL-License.
7  * Version lincan-0.3  17 Jun 2004
8  */ 
9
10 #include "../include/can.h"
11 #include "../include/can_sysdep.h"
12 #include "../include/main.h"
13 #include "../include/proc.h"
14 #include "../include/setup.h"
15
16 #define __NO_VERSION__
17 #include <linux/module.h>
18
19 int add_channel_to_procdir(struct candevice_t *candev);
20 int remove_channel_from_procdir(void);
21 int add_object_to_procdir(int chip_nr);
22 int remove_object_from_procdir(int chip_nr);
23
24 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
25 static int can_proc_readlink(struct proc_dir_entry *ent, char *page);
26 #endif
27
28 static int cc=0; /* static counter for each CAN chip */
29
30 static struct canproc_t can_proc_base;
31 static struct canproc_t *base=&can_proc_base;
32
33 /* The following functions are needed only for kernel version 2.2. Kernel
34  * version 2.4 already defines them for us.
35  */
36 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
37 static void can_fill_inode(struct inode *inode, int fill)
38 {
39         if (fill)
40                 MOD_INC_USE_COUNT;
41         else
42                 MOD_DEC_USE_COUNT;
43 }
44
45 static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
46                                         struct proc_dir_entry *parent)
47 {
48         struct proc_dir_entry *new_entry = NULL;
49         char *namestore;
50         int namelen;
51         
52         if(!name || !parent)
53                 return NULL;
54         namelen=strlen(name);
55         if(!namelen)
56                 return NULL;
57
58         new_entry = (struct proc_dir_entry *) 
59                         can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
60
61         if (new_entry == NULL)
62                 return NULL;
63
64         memset(new_entry, 0, sizeof(struct proc_dir_entry));
65
66         /* Store copy of the proc entry name */
67         namestore = ((char *) new_entry) + sizeof(struct proc_dir_entry);
68         memcpy(namestore, name, namelen + 1);
69
70         new_entry->low_ino = 0;
71         new_entry->namelen = namelen;
72         new_entry->name = namestore;
73         new_entry->mode = mode;
74         new_entry->nlink = 0;
75         new_entry->fill_inode = can_fill_inode;
76         new_entry->parent = parent;
77
78         proc_register(parent, new_entry);
79
80         return new_entry;
81 }
82
83 static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
84 {
85         if (del != NULL) {
86                 proc_unregister(parent, del->low_ino);
87                 can_checked_free(del);
88                 return 0;
89         }
90         else return -ENODEV;
91 }
92
93
94 static int can_proc_readlink(struct proc_dir_entry *ent, char *page)
95 {
96         char *link_dest = (char*)ent->data;
97         
98         strcpy(page, link_dest);
99         return strlen(link_dest);
100 }
101
102
103
104 /* This compatibility version of proc_symlink does not store local copy of destination */
105 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
106                 struct proc_dir_entry *parent, const char *dest)
107 {
108         struct proc_dir_entry *entry;
109         
110         
111         entry = can_create_proc_entry(name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, parent);
112         if (entry == NULL)
113                 return NULL;
114         entry->readlink_proc = can_proc_readlink;
115         entry->data = dest;
116         return entry;
117 }
118
119 #else /* Functions forwarded for kernel 2.4 and above */
120
121 static inline struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
122                                         struct proc_dir_entry *parent)
123 {
124         return create_proc_entry(name, mode, parent);
125 }
126
127
128 /* This does not fully follow linux 2.4 and 2.6 prototype to simplify 2.2.x compatibility */
129 /* The newer kernels use entry name instead of pointer to the entry */
130 static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
131 {
132         if(!del) return -ENODEV;
133         remove_proc_entry(del->name,parent);
134         return 0;
135 }
136
137 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
138                 struct proc_dir_entry *parent, const char *dest)
139 {
140         return proc_symlink(name, parent, dest);
141 }
142
143 #endif /* Functions required for kernel 2.2 */
144
145 /* can_init_procdir registers the entire CAN directory tree recursively at
146  * the proc system.
147  */
148 int can_init_procdir(void)
149 {
150         int board;
151         struct candevice_t *candev;
152         base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO | 
153                                         S_IXUGO, &proc_root);
154         if (base->can_proc_entry == NULL)
155                 return -ENODEV;
156
157         for (board=0; board<hardware_p->nr_boards; board++) {
158                 candev=hardware_p->candevice[board];
159                 if(candev) add_channel_to_procdir(candev);
160         } 
161
162         return 0;
163 }
164
165 /* can_delete_procdir removes the entire CAN tree from the proc system */
166 int can_delete_procdir(void)
167 {
168         if (remove_channel_from_procdir()) 
169                 return -ENODEV;
170         /* name: "can" */
171         if (can_remove_proc_entry(base->can_proc_entry, &proc_root)) 
172                 return -ENODEV;
173
174         return 0;
175 }
176
177 static int can_chip_procinfo(char *buf, char **start, off_t offset, 
178                  int count, int *eof, void *data)
179 {
180         struct canchip_t *chip=data;
181         int len=0;
182
183         /* Generic chip info */
184         len += sprintf(buf+len,"type    : %s\n",chip->chip_type);
185         len += sprintf(buf+len,"index   : %d\n",chip->chip_idx);
186         len += sprintf(buf+len,"irq     : %d\n",chip->chip_irq);
187         len += sprintf(buf+len,"addr    : %lu\n",
188                         can_ioptr2ulong(chip->chip_base_addr));
189         len += sprintf(buf+len,"config  : %s\n",
190                         (chip->flags & CHIP_CONFIGURED) ? "yes":"no");
191         len += sprintf(buf+len,"clock   : %ld Hz\n",chip->clock);
192         len += sprintf(buf+len,"baud    : %ld\n",chip->baudrate);
193         len += sprintf(buf+len,"num obj : %d\n",chip->max_objects);
194
195
196 #if 0
197         /* Chip specific info if available */
198         if(chip->chipspecops->get_info)
199                 len += (chip->chipspecops->get_info)(chip,buf+len);
200 #endif
201
202         *eof = 1;
203         return len;
204 }
205
206
207 int add_channel_to_procdir(struct candevice_t *candev)
208 {
209         int i=0;
210
211         for (i=0; i < candev->nr_all_chips; i++) {
212
213                 base->channel[cc] = (struct channelproc_t *)
214                         can_checked_malloc(sizeof(struct channelproc_t));
215                 if (base->channel[cc] == NULL)
216                         return -ENOMEM;
217
218                 sprintf(base->channel[cc]->ch_name, "channel%d",cc);
219                                                 
220                 base->channel[cc]->ch_entry = can_create_proc_entry(
221                                                 base->channel[cc]->ch_name,
222                                                 S_IFDIR | S_IRUGO |S_IXUGO,
223                                                 base->can_proc_entry);
224
225                 if (base->channel[cc]->ch_entry == NULL)
226                         return -ENODEV;
227
228                 add_object_to_procdir(cc);
229
230                 create_proc_read_entry("chip_info",        /* proc entry name */
231                                        0,                  /* protection mask, 0->default */
232                                        base->channel[cc]->ch_entry,  /* parent dir, NULL->/proc */
233                                        can_chip_procinfo,
234                                        candev->chip[i]);
235
236                 cc++;
237         } 
238
239         return 0;
240 }
241
242 int remove_channel_from_procdir(void)
243 {
244         
245         while (cc != 0) {
246                 cc--;
247                 
248                 if(!base->channel[cc]) continue;
249
250                 remove_proc_entry("chip_info", base->channel[cc]->ch_entry);
251                 
252                 if (remove_object_from_procdir(cc))
253                         return -ENODEV; 
254                         
255                 /* name: base->channel[cc]->ch_name */
256                 if (can_remove_proc_entry(base->channel[cc]->ch_entry,
257                                                         base->can_proc_entry))
258                         return -ENODEV;
259                         
260                 can_checked_free(base->channel[cc]);
261                 base->channel[cc] = NULL;
262         }
263
264         return 0;
265 }
266
267
268 int add_object_to_procdir(int chip_nr)
269 {
270         int i, max_objects;
271
272         max_objects=chips_p[chip_nr]->max_objects;
273
274         for (i=0; i<max_objects; i++) {
275                 base->channel[chip_nr]->object[i] = (struct objectproc_t *)
276                         can_checked_malloc(sizeof(struct objectproc_t));
277
278                 if (base->channel[chip_nr]->object[i] == NULL)
279                         return -ENOMEM;
280
281                 sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
282                 sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
283                                                                 
284                 base->channel[chip_nr]->object[i]->obj_entry = can_create_proc_entry(
285                                 base->channel[chip_nr]->object[i]->obj_name,
286                                 S_IFDIR | S_IRUGO | S_IXUGO,
287                                 base->channel[chip_nr]->ch_entry);
288                 if (base->channel[chip_nr]->object[i]->obj_entry == NULL)
289                         return -ENODEV;
290
291                 sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d",
292                         chips_p[chip_nr]->msgobj[i]->minor);
293
294                 base->channel[chip_nr]->object[i]->lnk = can_proc_symlink(
295                                 base->channel[chip_nr]->object[i]->lnk_name,
296                                 base->channel[chip_nr]->object[i]->obj_entry,
297                                 base->channel[chip_nr]->object[i]->lnk_dev);
298                 if (base->channel[chip_nr]->object[i]->lnk == NULL)
299                         return -ENODEV;
300
301         }
302         return 0;
303
304
305 int remove_object_from_procdir(int chip_nr)
306 {
307         int i=0, obj=0;
308
309         obj=chips_p[chip_nr]->max_objects;
310
311         for (i=0; i<obj; i++) {
312                 if(!base->channel[chip_nr]->object[i]) continue;
313                 
314                 /* name: base->channel[chip_nr]->object[i]->lnk_name */
315                 if (can_remove_proc_entry( base->channel[chip_nr]->object[i]->lnk,
316                                 base->channel[chip_nr]->object[i]->obj_entry))  
317                         return -ENODEV;
318                 /* name: base->channel[chip_nr]->object[i]->obj_name */
319                 if (can_remove_proc_entry(
320                                 base->channel[chip_nr]->object[i]->obj_entry,
321                                 base->channel[chip_nr]->ch_entry))
322                         return -ENODEV;
323
324                 can_checked_free(base->channel[chip_nr]->object[i]);
325
326                 base->channel[chip_nr]->object[i]=NULL;
327         }
328         return 0;
329 }
330