]> 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 /* 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 #include <linux/mutex.h>
19
20 int add_channel_to_procdir(struct candevice_t *candev);
21 int remove_channels_from_procdir(void);
22 int remove_channel_from_procdir(struct candevice_t *candev);
23 int add_object_to_procdir(int chip_nr);
24 int remove_object_from_procdir(int chip_nr);
25
26 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
27 static int can_proc_readlink(struct proc_dir_entry *ent, char *page);
28 #endif
29
30 #if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
31 #define CAN_PROC_ROOT (&proc_root)
32 #else /* >= 2.6.26 */
33 #define CAN_PROC_ROOT (NULL)
34 #endif /* >= 2.6.26 */
35
36 static int cc=0; /* static counter for each CAN chip */
37
38 static struct canproc_t can_proc_base;
39 static struct canproc_t *base=&can_proc_base;
40 DEFINE_MUTEX(proc_mutex);               /* synchronize access to canproc_t array */
41
42 /* The following functions are needed only for kernel version 2.2. Kernel
43  * version 2.4 already defines them for us.
44  */
45 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
46 static void can_fill_inode(struct inode *inode, int fill)
47 {
48         if (fill)
49                 MOD_INC_USE_COUNT;
50         else
51                 MOD_DEC_USE_COUNT;
52 }
53
54 static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
55                                         struct proc_dir_entry *parent)
56 {
57         struct proc_dir_entry *new_entry = NULL;
58         char *namestore;
59         int namelen;
60
61         if(!name || !parent)
62                 return NULL;
63         namelen=strlen(name);
64         if(!namelen)
65                 return NULL;
66
67         new_entry = (struct proc_dir_entry *)
68                         can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
69
70         if (new_entry == NULL)
71                 return NULL;
72
73         memset(new_entry, 0, sizeof(struct proc_dir_entry));
74
75         /* Store copy of the proc entry name */
76         namestore = ((char *) new_entry) + sizeof(struct proc_dir_entry);
77         memcpy(namestore, name, namelen + 1);
78
79         new_entry->low_ino = 0;
80         new_entry->namelen = namelen;
81         new_entry->name = namestore;
82         new_entry->mode = mode;
83         new_entry->nlink = 0;
84         new_entry->fill_inode = can_fill_inode;
85         new_entry->parent = parent;
86
87         proc_register(parent, new_entry);
88
89         return new_entry;
90 }
91
92 static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
93 {
94         if (del != NULL) {
95                 proc_unregister(parent, del->low_ino);
96                 can_checked_free(del);
97                 return 0;
98         }
99         else return -ENODEV;
100 }
101
102
103 static int can_proc_readlink(struct proc_dir_entry *ent, char *page)
104 {
105         char *link_dest = (char*)ent->data;
106
107         strcpy(page, link_dest);
108         return strlen(link_dest);
109 }
110
111
112
113 /* This compatibility version of proc_symlink does not store local copy of destination */
114 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
115                 struct proc_dir_entry *parent, const char *dest)
116 {
117         struct proc_dir_entry *entry;
118
119
120         entry = can_create_proc_entry(name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, parent);
121         if (entry == NULL)
122                 return NULL;
123         entry->readlink_proc = can_proc_readlink;
124         entry->data = dest;
125         return entry;
126 }
127
128 #else /* Functions forwarded for kernel 2.4 and above */
129
130 static inline struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
131                                         struct proc_dir_entry *parent)
132 {
133         return create_proc_entry(name, mode, parent);
134 }
135
136
137 /* This does not fully follow linux 2.4 and 2.6 prototype to simplify 2.2.x compatibility */
138 /* The newer kernels use entry name instead of pointer to the entry */
139 static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
140 {
141         if(!del) return -ENODEV;
142         remove_proc_entry(del->name,parent);
143         return 0;
144 }
145
146 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
147                 struct proc_dir_entry *parent, const char *dest)
148 {
149         return proc_symlink(name, parent, dest);
150 }
151
152 #endif /* Functions required for kernel 2.2 */
153
154 /* can_init_procdir registers the entire CAN directory tree recursively at
155  * the proc system.
156  */
157 int can_init_procdir(void)
158 {
159         int board;
160         struct candevice_t *candev;
161
162         mutex_init(&proc_mutex);
163
164         base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO |
165                                         S_IXUGO, CAN_PROC_ROOT);
166         if (base->can_proc_entry == NULL)
167                 return -ENODEV;
168
169         for (board=0; board<hardware_p->nr_boards; board++) {
170                 candev=hardware_p->candevice[board];
171                 if(candev) add_channel_to_procdir(candev);
172         }
173
174         return 0;
175 }
176
177 /* can_init_procentry registers entry of a new board in CAN directory tree at
178  * the proc system.
179  */
180 int can_init_procentry(int board)
181 {
182         struct candevice_t *candev;
183         candev=hardware_p->candevice[board];
184         if(candev)
185                 return add_channel_to_procdir(candev);
186         return -ENODEV;
187 }
188
189 /* can_delete_procdir removes the entire CAN tree from the proc system */
190 int can_delete_procdir(void)
191 {
192         if (remove_channels_from_procdir())
193                 return -ENODEV;
194         /* name: "can" */
195         if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT))
196                 return -ENODEV;
197
198         return 0;
199 }
200
201 /* can_delete_procentry removes device entries from CAN tree in the proc system */
202 int can_delete_procentry(struct candevice_t *candev)
203 {
204         if (remove_channel_from_procdir(candev))
205                 return -ENODEV;
206
207         return 0;
208 }
209
210 static int can_chip_procinfo(char *buf, char **start, off_t offset,
211                  int count, int *eof, void *data)
212 {
213         struct canchip_t *chip=data;
214         int len=0;
215
216         /* Generic chip info */
217         len += sprintf(buf+len,"type    : %s\n",chip->chip_type);
218         len += sprintf(buf+len,"index   : %d\n",chip->chip_idx);
219         len += sprintf(buf+len,"irq     : %d\n",chip->chip_irq);
220         len += sprintf(buf+len,"addr    : %lu\n",
221                         can_ioptr2ulong(chip->chip_base_addr));
222         len += sprintf(buf+len,"config  : %s\n",
223                         (chip->flags & CHIP_CONFIGURED) ? "yes":"no");
224         len += sprintf(buf+len,"clock   : %ld Hz\n",chip->clock);
225         len += sprintf(buf+len,"baud    : %ld\n",chip->baudrate);
226         len += sprintf(buf+len,"num obj : %d\n",chip->max_objects);
227
228
229 #if 0
230         /* Chip specific info if available */
231         if(chip->chipspecops->get_info)
232                 len += (chip->chipspecops->get_info)(chip,buf+len);
233 #endif
234
235         *eof = 1;
236         return len;
237 }
238
239
240 int add_channel_to_procdir(struct candevice_t *candev)
241 {
242         int i=0;
243
244         mutex_lock(&proc_mutex);
245         for (i=0; i < MAX_TOT_CHIPS; i++){
246                 if (!chips_p[i]) continue;
247                 if (chips_p[i]->hostdevice != candev) continue;
248
249                 base->channel[i] = (struct channelproc_t *)
250                         can_checked_malloc(sizeof(struct channelproc_t));
251                 if (base->channel[i] == NULL){
252                         mutex_unlock(&proc_mutex);
253                         return -ENOMEM;
254                 }
255
256                 sprintf(base->channel[i]->ch_name, "channel%d",i);
257
258                 base->channel[i]->ch_entry = can_create_proc_entry(
259                                                 base->channel[i]->ch_name,
260                                                 S_IFDIR | S_IRUGO |S_IXUGO,
261                                                 base->can_proc_entry);
262
263                 if (base->channel[i]->ch_entry == NULL){
264                         mutex_unlock(&proc_mutex);
265                         return -ENODEV;
266                 }
267
268                 add_object_to_procdir(i);
269
270                 create_proc_read_entry("chip_info",        /* proc entry name */
271                                        0,                  /* protection mask, 0->default */
272                                        base->channel[i]->ch_entry,  /* parent dir, NULL->/proc */
273                                        can_chip_procinfo,
274                                        chips_p[i]);
275                 cc++;
276         }
277         mutex_unlock(&proc_mutex);
278
279         return 0;
280 }
281
282 int remove_channels_from_procdir(void)
283 {
284         int i=0;
285
286         mutex_lock(&proc_mutex);
287         for (i=0; i < MAX_TOT_CHIPS; i++){
288                 if (!chips_p[i]) continue;
289
290                 cc--;
291
292                 if(!base->channel[i]) continue;
293
294                 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
295
296                 if (remove_object_from_procdir(i)){
297                         mutex_unlock(&proc_mutex);
298                         return -ENODEV;
299                 }
300
301                 /* name: base->channel[cc]->ch_name */
302                 if (can_remove_proc_entry(base->channel[i]->ch_entry,
303                                                         base->can_proc_entry)){
304                         mutex_unlock(&proc_mutex);
305                         return -ENODEV;
306                 }
307
308                 can_checked_free(base->channel[i]);
309                 base->channel[i] = NULL;
310         }
311         mutex_unlock(&proc_mutex);
312
313         return 0;
314 }
315
316 int remove_channel_from_procdir(struct candevice_t *candev)
317 {
318         int i=0,j=0;
319
320         mutex_lock(&proc_mutex);
321         for (i=0; i < MAX_TOT_CHIPS; i++){
322                 if (!chips_p[i]) continue;
323                 if (chips_p[i]->hostdevice != candev) continue;
324                 if (!base->channel[i]) continue;
325
326                 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
327
328                 if (remove_object_from_procdir(i)){
329                         mutex_unlock(&proc_mutex);
330                         return -ENODEV;
331                 }
332
333                 /* name: base->channel[cc]->ch_name */
334                 if (can_remove_proc_entry(base->channel[i]->ch_entry,
335                                                         base->can_proc_entry)){
336                         mutex_unlock(&proc_mutex);
337                         return -ENODEV;
338                 }
339
340                 can_checked_free(base->channel[i]);
341                 base->channel[i] = NULL;
342
343                 cc--;
344         }
345         mutex_unlock(&proc_mutex);
346
347         return 0;
348 }
349
350
351 int add_object_to_procdir(int chip_nr)
352 {
353         int i, max_objects;
354
355         max_objects=chips_p[chip_nr]->max_objects;
356
357         for (i=0; i<max_objects; i++) {
358                 base->channel[chip_nr]->object[i] = (struct objectproc_t *)
359                         can_checked_malloc(sizeof(struct objectproc_t));
360
361                 if (base->channel[chip_nr]->object[i] == NULL)
362                         return -ENOMEM;
363
364                 sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
365                 sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
366
367                 base->channel[chip_nr]->object[i]->obj_entry = can_create_proc_entry(
368                                 base->channel[chip_nr]->object[i]->obj_name,
369                                 S_IFDIR | S_IRUGO | S_IXUGO,
370                                 base->channel[chip_nr]->ch_entry);
371                 if (base->channel[chip_nr]->object[i]->obj_entry == NULL)
372                         return -ENODEV;
373
374                 sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d",
375                         chips_p[chip_nr]->msgobj[i]->minor);
376
377                 base->channel[chip_nr]->object[i]->lnk = can_proc_symlink(
378                                 base->channel[chip_nr]->object[i]->lnk_name,
379                                 base->channel[chip_nr]->object[i]->obj_entry,
380                                 base->channel[chip_nr]->object[i]->lnk_dev);
381                 if (base->channel[chip_nr]->object[i]->lnk == NULL)
382                         return -ENODEV;
383
384         }
385         return 0;
386 }
387
388 int remove_object_from_procdir(int chip_nr)
389 {
390         int i=0, obj=0;
391
392         obj=chips_p[chip_nr]->max_objects;
393
394         for (i=0; i<obj; i++) {
395                 if(!base->channel[chip_nr]->object[i]) continue;
396
397                 /* name: base->channel[chip_nr]->object[i]->lnk_name */
398                 if (can_remove_proc_entry( base->channel[chip_nr]->object[i]->lnk,
399                                 base->channel[chip_nr]->object[i]->obj_entry))
400                         return -ENODEV;
401                 /* name: base->channel[chip_nr]->object[i]->obj_name */
402                 if (can_remove_proc_entry(
403                                 base->channel[chip_nr]->object[i]->obj_entry,
404                                 base->channel[chip_nr]->ch_entry))
405                         return -ENODEV;
406
407                 can_checked_free(base->channel[chip_nr]->object[i]);
408
409                 base->channel[chip_nr]->object[i]=NULL;
410         }
411         return 0;
412 }
413