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