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