]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/proc.c
CAN driver infrastructure redesign to LinCAN-0.2 version
[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.2  9 Jul 2003
8  */ 
9
10 #define __NO_VERSION__
11 #include <linux/module.h>
12
13 #include <linux/autoconf.h>
14
15 #include <linux/version.h>
16 #include <linux/kernel.h>
17 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
18 #include <linux/malloc.h>
19 #else
20 #include <linux/slab.h>
21 #endif
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(struct candevice_t *candev);
30 int remove_channel_from_procdir(void);
31 int add_object_to_procdir(int chip_nr);
32 int remove_object_from_procdir(void);
33
34 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
35 static int candev_readlink(struct proc_dir_entry *de, char *page);
36 #endif
37
38 static int cc=0; /* static counter for each CAN chip */
39
40 struct canproc_t can_proc_base;
41 struct canproc_t *base=&can_proc_base;
42
43 /* The following functions are needed only for kernel version 2.2. Kernel
44  * version 2.4 already defines them for us.
45  */
46 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
47 static void can_fill_inode(struct inode *inode, int fill)
48 {
49         if (fill)
50                 MOD_INC_USE_COUNT;
51         else
52                 MOD_DEC_USE_COUNT;
53 }
54
55 static struct proc_dir_entry * new_can_proc_entry(unsigned short inode,
56     const char *name, mode_t mode, nlink_t nlink, struct proc_dir_entry *parent)
57 {
58         struct proc_dir_entry *new_entry = NULL;
59
60         new_entry = (struct proc_dir_entry *) kmalloc(sizeof(struct 
61                                                 proc_dir_entry), GFP_KERNEL);
62         if (new_entry == NULL)
63                 return NULL;
64
65         memset(new_entry, 0, sizeof(struct proc_dir_entry));
66
67         new_entry->low_ino = inode;
68         new_entry->namelen = strlen(name);
69         new_entry->name = name;
70         new_entry->mode = mode;
71         new_entry->nlink = nlink;
72         new_entry->fill_inode = can_fill_inode;
73         new_entry->parent = parent;
74
75         proc_register(parent, new_entry);
76
77         return new_entry;
78 }
79
80 int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
81 {
82         if (del != NULL) {
83                 proc_unregister(parent, del->low_ino);
84                 kfree(del);
85                 del = NULL;
86                 return 0;
87         }
88         else return -ENODEV;
89 }
90 #endif // Functions required for kernel 2.2
91
92 /* can_init_procdir registers the entire CAN directory tree recursively at
93  * the proc system.
94  */
95 int can_init_procdir(void)
96 {
97         int board;
98         struct candevice_t *candev;
99 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
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 (board=0; board<hardware_p->nr_boards; board++) {
110                 candev=hardware_p->candevice[board];
111                 if(candev) add_channel_to_procdir(candev);
112         } 
113
114         return 0;
115 }
116
117 /* can_delete_procdir removes the entire CAN tree from the proc system */
118 int can_delete_procdir(void)
119 {
120         if (remove_channel_from_procdir()) 
121                 return -ENODEV;
122 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
123         if (can_remove_proc_entry(base->can_proc_entry, &proc_root)) 
124                 return -ENODEV;
125 #else
126         remove_proc_entry("can", &proc_root);
127 #endif
128
129         return 0;
130 }
131
132 int add_channel_to_procdir(struct candevice_t *candev)
133 {
134         int i=0;
135
136         for (i=0; i < candev->nr_all_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,3,0))
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(cc);
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,3,0))
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(int chip_nr)
191 {
192         int i, max_objects;
193
194         max_objects=chips_p[chip_nr]->max_objects;
195
196         for (i=0; i<max_objects; i++) {
197                 base->channel[chip_nr]->object[i] = (struct objectproc_t *)
198                         kmalloc(sizeof(struct objectproc_t),GFP_KERNEL);
199                                 
200                                 
201                 if (base->channel[chip_nr]->object[i] == NULL)
202                         return -ENOMEM;
203                 else if (add_mem_to_list( base->channel[chip_nr]->object[i]))
204                         return -ENOMEM;
205
206                 sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
207                 sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
208                                                                 
209 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
210                 base->channel[chip_nr]->object[i]->obj_entry=new_can_proc_entry(
211                                 0, base->channel[chip_nr]->object[i]->obj_name,
212                                 S_IFDIR | S_IRUGO | S_IXUGO, 0, 
213                                 base->channel[chip_nr]->ch_entry);
214                 if (base->channel[chip_nr]->object[i]->obj_entry == NULL)
215                         return -ENODEV;
216                 base->channel[chip_nr]->object[i]->lnk = new_can_proc_entry(
217                                 0, base->channel[chip_nr]->object[i]->lnk_name, 
218                                 S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO,
219                                 0, base->channel[chip_nr]->object[i]->obj_entry);
220                 if (base->channel[chip_nr]->object[i]->lnk == NULL)
221                         return -ENODEV;
222                 sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can");
223                 base->channel[chip_nr]->object[i]->lnk->readlink_proc =
224                                                                 candev_readlink;
225
226 #else
227                 base->channel[chip_nr]->object[i]->obj_entry = create_proc_entry(
228                                 base->channel[chip_nr]->object[i]->obj_name,
229                                 S_IFDIR | S_IRUGO | S_IXUGO,
230                                 base->channel[chip_nr]->ch_entry);
231                 if (base->channel[chip_nr]->object[i]->obj_entry == NULL)
232                         return -ENODEV;
233                 sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d",
234                         chips_p[chip_nr]->msgobj[i]->minor);
235                 base->channel[chip_nr]->object[i]->lnk = proc_symlink(
236                                 base->channel[chip_nr]->object[i]->lnk_name,
237                                 base->channel[chip_nr]->object[i]->obj_entry,
238                                 base->channel[chip_nr]->object[i]->lnk_dev);
239                 if (base->channel[chip_nr]->object[i]->lnk == NULL)
240                         return -ENODEV;
241 #endif
242
243         }
244         return 0;
245
246
247 int remove_object_from_procdir(void)
248 {
249         int i=0, obj=0;
250
251         obj=chips_p[cc]->max_objects;
252
253         for (i=0; i<obj; i++) {
254 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
255                 if (can_remove_proc_entry( base->channel[cc]->object[i]->lnk,
256                                 base->channel[cc]->object[i]->obj_entry))       
257                         return -ENODEV;
258                 if (can_remove_proc_entry(
259                                 base->channel[cc]->object[i]->obj_entry,
260                                 base->channel[cc]->ch_entry))
261                         return -ENODEV;
262 #else
263                 remove_proc_entry(base->channel[cc]->object[i]->lnk_name,
264                                 base->channel[cc]->object[i]->obj_entry);
265                 remove_proc_entry(base->channel[cc]->object[i]->obj_name,
266                                         base->channel[cc]->ch_entry);
267 #endif
268                 
269         }
270         return 0;
271 }
272
273 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
274 static int candev_readlink(struct proc_dir_entry *de, char *page)
275 {
276         int i=0, nchip=0, nobj=0;
277         char chip[20], object[20], tmp[6];
278
279         sprintf(chip, de->parent->parent->name+7);
280         sprintf(object, de->parent->name+6);
281
282         for (i=0; i<MAX_TOT_CHIPS; i++) {
283                 sprintf(tmp,"%d",i);
284                 if (!strcmp(chip,tmp)) {
285                         nchip=i;
286                         break;
287                 }       
288         }
289         for (i=0; i<MAX_MSGOBJS; i++) {
290                 sprintf(tmp,"%d",i);
291                 if (!strcmp(object,tmp)) {
292                         nobj=i;
293                         break;
294                 }
295         }
296
297         return sprintf(page,"/dev/can%d",chips_p[nchip]->msgobj[nobj]->minor );
298 }
299 #endif //End of candev_readlink for kernel 2.2