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
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"
16 #define __NO_VERSION__
17 #include <linux/module.h>
18 #include <linux/mutex.h>
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);
26 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
27 static int can_proc_readlink(struct proc_dir_entry *ent, char *page);
30 static int cc=0; /* static counter for each CAN chip */
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 */
36 /* The following functions are needed only for kernel version 2.2. Kernel
37 * version 2.4 already defines them for us.
39 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
40 static void can_fill_inode(struct inode *inode, int fill)
48 static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
49 struct proc_dir_entry *parent)
51 struct proc_dir_entry *new_entry = NULL;
61 new_entry = (struct proc_dir_entry *)
62 can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1);
64 if (new_entry == NULL)
67 memset(new_entry, 0, sizeof(struct proc_dir_entry));
69 /* Store copy of the proc entry name */
70 namestore = ((char *) new_entry) + sizeof(struct proc_dir_entry);
71 memcpy(namestore, name, namelen + 1);
73 new_entry->low_ino = 0;
74 new_entry->namelen = namelen;
75 new_entry->name = namestore;
76 new_entry->mode = mode;
78 new_entry->fill_inode = can_fill_inode;
79 new_entry->parent = parent;
81 proc_register(parent, new_entry);
86 static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
89 proc_unregister(parent, del->low_ino);
90 can_checked_free(del);
97 static int can_proc_readlink(struct proc_dir_entry *ent, char *page)
99 char *link_dest = (char*)ent->data;
101 strcpy(page, link_dest);
102 return strlen(link_dest);
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)
111 struct proc_dir_entry *entry;
114 entry = can_create_proc_entry(name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, parent);
117 entry->readlink_proc = can_proc_readlink;
122 #else /* Functions forwarded for kernel 2.4 and above */
124 static inline struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode,
125 struct proc_dir_entry *parent)
127 return create_proc_entry(name, mode, parent);
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)
135 if(!del) return -ENODEV;
136 remove_proc_entry(del->name,parent);
140 static inline struct proc_dir_entry *can_proc_symlink(const char *name,
141 struct proc_dir_entry *parent, const char *dest)
143 return proc_symlink(name, parent, dest);
146 #endif /* Functions required for kernel 2.2 */
148 /* can_init_procdir registers the entire CAN directory tree recursively at
151 int can_init_procdir(void)
154 struct candevice_t *candev;
156 mutex_init(&proc_mutex);
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)
163 for (board=0; board<hardware_p->nr_boards; board++) {
164 candev=hardware_p->candevice[board];
165 if(candev) add_channel_to_procdir(candev);
171 /* can_init_procentry registers entry of a new board in CAN directory tree at
174 int can_init_procentry(int board)
176 struct candevice_t *candev;
177 candev=hardware_p->candevice[board];
179 return add_channel_to_procdir(candev);
183 /* can_delete_procdir removes the entire CAN tree from the proc system */
184 int can_delete_procdir(void)
186 if (remove_channels_from_procdir())
189 if (can_remove_proc_entry(base->can_proc_entry, &proc_root))
195 /* can_delete_procentry removes device entries from CAN tree in the proc system */
196 int can_delete_procentry(struct candevice_t *candev)
198 if (remove_channel_from_procdir(candev))
204 static int can_chip_procinfo(char *buf, char **start, off_t offset,
205 int count, int *eof, void *data)
207 struct canchip_t *chip=data;
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);
223 /* Chip specific info if available */
224 if(chip->chipspecops->get_info)
225 len += (chip->chipspecops->get_info)(chip,buf+len);
233 int add_channel_to_procdir(struct candevice_t *candev)
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;
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);
249 sprintf(base->channel[i]->ch_name, "channel%d",i);
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);
256 if (base->channel[i]->ch_entry == NULL){
257 mutex_unlock(&proc_mutex);
261 add_object_to_procdir(i);
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 */
270 mutex_unlock(&proc_mutex);
275 int remove_channels_from_procdir(void)
279 mutex_lock(&proc_mutex);
280 for (i=0; i < MAX_TOT_CHIPS; i++){
281 if (!chips_p[i]) continue;
285 if(!base->channel[i]) continue;
287 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
289 if (remove_object_from_procdir(i)){
290 mutex_unlock(&proc_mutex);
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);
301 can_checked_free(base->channel[i]);
302 base->channel[i] = NULL;
304 mutex_unlock(&proc_mutex);
309 int remove_channel_from_procdir(struct candevice_t *candev)
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;
319 remove_proc_entry("chip_info", base->channel[i]->ch_entry);
321 if (remove_object_from_procdir(i)){
322 mutex_unlock(&proc_mutex);
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);
333 can_checked_free(base->channel[i]);
334 base->channel[i] = NULL;
338 mutex_unlock(&proc_mutex);
344 int add_object_to_procdir(int chip_nr)
348 max_objects=chips_p[chip_nr]->max_objects;
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));
354 if (base->channel[chip_nr]->object[i] == NULL)
357 sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i);
358 sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev");
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)
367 sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d",
368 chips_p[chip_nr]->msgobj[i]->minor);
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)
381 int remove_object_from_procdir(int chip_nr)
385 obj=chips_p[chip_nr]->max_objects;
387 for (i=0; i<obj; i++) {
388 if(!base->channel[chip_nr]->object[i]) continue;
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))
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))
400 can_checked_free(base->channel[chip_nr]->object[i]);
402 base->channel[chip_nr]->object[i]=NULL;