]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/proc.c
79309e0e35affbe900df17959b6da583c85438fe
[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  * This software is released under the GPL-License.
5  * Version 0.7  6 Aug 2001
6  */ 
7
8 #define __NO_VERSION__
9 #include <linux/module.h>
10
11 #include <linux/autoconf.h>
12 #if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
13 #define MODVERSIONS
14 #endif
15
16 #if defined (MODVERSIONS)
17 #include <linux/modversions.h>
18 #endif
19
20 #include <linux/version.h>
21 #include <linux/kernel.h>
22 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
23 #include <linux/malloc.h>
24 #else
25 #include <linux/slab.h>
26 #endif
27 #include <linux/proc_fs.h>
28 #include <linux/version.h>
29
30 #include "../include/main.h"
31 #include "../include/proc.h"
32 #include "../include/setup.h"
33
34 int add_channel_to_procdir(void);
35 int remove_channel_from_procdir(void);
36 int add_object_to_procdir(void);
37 int remove_object_from_procdir(void);
38
39 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
40 static int candev_readlink(struct proc_dir_entry *de, char *page);
41 #endif
42
43 static int bc=0; /* static counter for each hardware board */
44 static int cc=0; /* static counter for each CAN chip */
45 static int oc=0; /* static counter for each message object */
46
47 struct canproc_t can_proc_base;
48 struct canproc_t *base=&can_proc_base;
49
50 /* The following functions are needed only for kernel version 2.2. Kernel
51  * version 2.4 already defines them for us.
52  */
53 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
54 static void can_fill_inode(struct inode *inode, int fill)
55 {
56         if (fill)
57                 MOD_INC_USE_COUNT;
58         else
59                 MOD_DEC_USE_COUNT;
60 }
61
62 static struct proc_dir_entry * new_can_proc_entry(unsigned short inode,
63     const char *name, mode_t mode, nlink_t nlink, struct proc_dir_entry *parent)
64 {
65         struct proc_dir_entry *new_entry = NULL;
66
67         new_entry = (struct proc_dir_entry *) kmalloc(sizeof(struct 
68                                                 proc_dir_entry), GFP_KERNEL);
69         if (new_entry == NULL)
70                 return NULL;
71
72         memset(new_entry, 0, sizeof(struct proc_dir_entry));
73
74         new_entry->low_ino = inode;
75         new_entry->namelen = strlen(name);
76         new_entry->name = name;
77         new_entry->mode = mode;
78         new_entry->nlink = nlink;
79         new_entry->fill_inode = can_fill_inode;
80         new_entry->parent = parent;
81
82         proc_register(parent, new_entry);
83
84         return new_entry;
85 }
86
87 int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
88 {
89         if (del != NULL) {
90                 proc_unregister(parent, del->low_ino);
91                 kfree(del);
92                 del = NULL;
93                 return 0;
94         }
95         else return -ENODEV;
96 }
97 #endif // Functions required for kernel 2.2
98
99 /* can_init_procdir registers the entire CAN directory tree recursively at
100  * the proc system.
101  */
102 int can_init_procdir(void)
103 {
104 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
105         base->can_proc_entry = new_can_proc_entry(0, "can", S_IFDIR | S_IRUGO | 
106                                         S_IXUGO, 0, &proc_root);
107 #else
108         base->can_proc_entry = create_proc_entry("can", S_IFDIR | S_IRUGO | 
109                                         S_IXUGO, &proc_root);
110 #endif
111         if (base->can_proc_entry == NULL)
112                 return -ENODEV;
113
114         for (bc=0; bc<hardware_p->nr_boards; bc++) {
115                 add_channel_to_procdir();
116         } 
117
118         return 0;
119 }
120
121 /* can_delete_procdir removes the entire CAN tree from the proc system */
122 int can_delete_procdir(void)
123 {
124         if (remove_channel_from_procdir()) 
125                 return -ENODEV;
126 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
127         if (can_remove_proc_entry(base->can_proc_entry, &proc_root)) 
128                 return -ENODEV;
129 #else
130         remove_proc_entry("can", &proc_root);
131 #endif
132
133         return 0;
134 }
135
136 int add_channel_to_procdir(void)
137 {
138         int i=0;
139
140         for (i=0; i < candevices_p[bc]->nr_82527_chips + 
141                         candevices_p[bc]->nr_sja1000_chips; i++) {
142
143                 base->channel[cc] = (struct channelproc_t *)
144                         kmalloc(sizeof(struct channelproc_t), GFP_KERNEL);
145                 if (base->channel[cc] == NULL)
146                         return -ENOMEM;
147                 else if (add_mem_to_list(base->channel[cc]))
148                         return -ENOMEM;
149
150                 sprintf(base->channel[cc]->ch_name, "channel%d",cc);
151                                                 
152 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
153                 base->channel[cc]->ch_entry = new_can_proc_entry(0, 
154                                                 base->channel[cc]->ch_name,
155                                                 S_IFDIR | S_IRUGO | S_IXUGO, 0, 
156                                                 base->can_proc_entry);
157 #else
158                 base->channel[cc]->ch_entry = create_proc_entry(
159                                                 base->channel[cc]->ch_name,
160                                                 S_IFDIR | S_IRUGO |S_IXUGO,
161                                                 base->can_proc_entry);
162 #endif
163                 if (base->channel[cc]->ch_entry == NULL)
164                         return -ENODEV;
165
166                 add_object_to_procdir();
167
168                 cc++;
169         } 
170
171         return 0;
172 }
173
174 int remove_channel_from_procdir(void)
175 {
176         
177         while (cc != 0) {
178                 cc--;
179 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
180                 if (can_remove_proc_entry(base->channel[cc]->ch_entry,
181                                                         base->can_proc_entry))
182                         return -ENODEV;
183 #else
184                 remove_proc_entry(base->channel[cc]->ch_name,
185                                                         base->can_proc_entry);
186 #endif
187                 if (remove_object_from_procdir())
188                         return -ENODEV; 
189         }
190
191         return 0;
192 }
193
194
195 int add_object_to_procdir(void)
196 {
197         int i=0, obj=0;
198
199         if (!strcmp(chips_p[cc]->chip_type,"i82527"))
200                 obj=15;
201         if (!strcmp(chips_p[cc]->chip_type,"sja1000"))
202                 obj=1;
203
204         for (i=0; i<obj; i++) {
205                 oc=i;
206                 base->channel[cc]->object[i] = (struct objectproc_t *)
207                         kmalloc(sizeof(struct objectproc_t),GFP_KERNEL);
208                                 
209                                 
210                 if (base->channel[cc]->object[i] == NULL)
211                         return -ENOMEM;
212                 else if (add_mem_to_list( base->channel[cc]->object[i]))
213                         return -ENOMEM;
214
215                 sprintf(base->channel[cc]->object[i]->obj_name,"object%d",i);
216                 sprintf(base->channel[cc]->object[i]->lnk_name,"dev");
217                                                                 
218 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
219                 base->channel[cc]->object[i]->obj_entry=new_can_proc_entry(
220                                 0, base->channel[cc]->object[i]->obj_name,
221                                 S_IFDIR | S_IRUGO | S_IXUGO, 0, 
222                                 base->channel[cc]->ch_entry);
223                 if (base->channel[cc]->object[i]->obj_entry == NULL)
224                         return -ENODEV;
225                 base->channel[cc]->object[i]->lnk = new_can_proc_entry(
226                                 0, base->channel[cc]->object[i]->lnk_name, 
227                                 S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO,
228                                 0, base->channel[cc]->object[i]->obj_entry);
229                 if (base->channel[cc]->object[i]->lnk == NULL)
230                         return -ENODEV;
231                 sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/can");
232                 base->channel[cc]->object[i]->lnk->readlink_proc =
233                                                                 candev_readlink;
234
235 #else
236                 base->channel[cc]->object[i]->obj_entry = create_proc_entry(
237                                 base->channel[cc]->object[i]->obj_name,
238                                 S_IFDIR | S_IRUGO | S_IXUGO,
239                                 base->channel[cc]->ch_entry);
240                 if (base->channel[cc]->object[i]->obj_entry == NULL)
241                         return -ENODEV;
242                 sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/can%d",
243                         chips_p[cc]->msgobj[i]->minor);
244                 base->channel[cc]->object[i]->lnk = proc_symlink(
245                                 base->channel[cc]->object[i]->lnk_name,
246                                 base->channel[cc]->object[i]->obj_entry,
247                                 base->channel[cc]->object[i]->lnk_dev);
248                 if (base->channel[cc]->object[i]->lnk == NULL)
249                         return -ENODEV;
250 #endif
251
252         }
253         return 0;
254
255
256 int remove_object_from_procdir(void)
257 {
258         int i=0, obj=0;
259
260         if (!strcmp(chips_p[cc]->chip_type,"i82527"))
261                 obj=15;
262         if (!strcmp(chips_p[cc]->chip_type,"sja1000"))
263                 obj=1;
264
265         for (i=0; i<obj; i++) {
266 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
267                 if (can_remove_proc_entry( base->channel[cc]->object[i]->lnk,
268                                 base->channel[cc]->object[i]->obj_entry))       
269                         return -ENODEV;
270                 if (can_remove_proc_entry(
271                                 base->channel[cc]->object[i]->obj_entry,
272                                 base->channel[cc]->ch_entry))
273                         return -ENODEV;
274 #else
275                 remove_proc_entry(base->channel[cc]->object[i]->lnk_name,
276                                 base->channel[cc]->object[i]->obj_entry);
277                 remove_proc_entry(base->channel[cc]->object[i]->obj_name,
278                                         base->channel[cc]->ch_entry);
279 #endif
280                 
281         }
282         return 0;
283 }
284
285 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
286 static int candev_readlink(struct proc_dir_entry *de, char *page)
287 {
288         int i=0, nchip=0, nobj=0;
289         char chip[20], object[20], tmp[6];
290
291         sprintf(chip, de->parent->parent->name+7);
292         sprintf(object, de->parent->name+6);
293
294         for (i=0; i<MAX_TOT_CHIPS; i++) {
295                 sprintf(tmp,"%d",i);
296                 if (!strcmp(chip,tmp)) {
297                         nchip=i;
298                         break;
299                 }       
300         }
301         for (i=0; i<MAX_MSGOBJS; i++) {
302                 sprintf(tmp,"%d",i);
303                 if (!strcmp(object,tmp)) {
304                         nobj=i;
305                         break;
306                 }
307         }
308
309         return sprintf(page,"/dev/can%d",chips_p[nchip]->msgobj[nobj]->minor );
310 }
311 #endif //End of candev_readlink for kernel 2.2