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