]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/setup.c
49b43153994e672d3dd04fc5e16f7286f437d9e2
[lincan.git] / lincan / src / setup.c
1 /* setup.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 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
17 #include <linux/malloc.h>
18 #else
19 #include <linux/slab.h>
20 #endif
21 #include <linux/fs.h>
22 #include <linux/ioport.h>
23
24 #include "../include/main.h"
25 #include "../include/devcommon.h"
26 #include "../include/setup.h"
27
28 extern int sja1000_register(struct chipspecops_t *chipspecops);
29 extern int sja1000p_register(struct chipspecops_t *chipspecops);
30 extern int i82527_register(struct chipspecops_t *chipspecops);
31
32 int init_device_struct(int card);
33 int init_hwspecops(struct candevice_t *candev);
34 int init_chip_struct(struct candevice_t *candev);
35 int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase);
36 int init_chipspecops(struct candevice_t *candev, int chipnr);
37
38 int add_mem_to_list(void *address_p)
39 {
40         struct mem_addr *mem_new;
41
42 #ifdef DEBUG_MEM
43         DEBUGMSG("add_mem_to_list %p, mem_head=%p\n",address_p, mem_head);
44         return 0;
45 #endif
46
47         mem_new=(struct mem_addr *)kmalloc(sizeof(struct mem_addr),GFP_KERNEL);
48         if (mem_new == NULL) {
49                 CANMSG("Memory list error.\n");
50                 return -ENOMEM;
51         }
52         mem_new->next=mem_head;
53         mem_new->address=address_p;
54         mem_head=mem_new;
55
56         return 0;
57 }
58
59 int del_mem_from_list(void *address_p)
60 {
61         struct mem_addr *mem_search=NULL;
62         struct mem_addr *mem_delete=NULL;
63
64 #ifdef DEBUG_MEM
65         DEBUGMSG("del_mem_from_list %p, mem_head=%p\n", address_p, mem_head);
66         return 0;
67 #endif
68         if(mem_head == NULL) {
69                 CANMSG("del_mem_from_list: mem_head == NULL address_p=%p!\n",
70                                 address_p);
71                 return 0;
72         }
73
74         mem_search = mem_head;
75
76         if (mem_head->address == address_p) {
77                 kfree(mem_head->address);
78                 mem_head=mem_head->next;
79                 kfree(mem_search);
80         }
81         else {
82                 while (mem_search->next->address != address_p)
83                         mem_search=mem_search->next;
84                 kfree(mem_search->next->address);               
85                 mem_delete=mem_search->next;
86                 mem_search->next=mem_search->next->next;
87                 kfree(mem_delete);
88         }
89         return 0;
90 }
91
92
93 int del_mem_list(void)
94 {
95         struct mem_addr *mem_old;
96
97 #ifdef DEBUG_MEM
98         DEBUGMSG("del_mem_list, mem_head=%p\n", mem_head);
99         return 0;
100 #endif
101         if(mem_head == NULL) {
102                 CANMSG("del_mem_list: mem_head == NULL!\n");
103                 return 0;
104         }
105
106         while (mem_head->next != NULL) {
107                 mem_old=mem_head;
108                 kfree(mem_old->address);
109                 mem_head=mem_old->next;
110                 kfree(mem_old);
111         }
112         
113         return 0;
114 }
115
116 int can_request_io_region(unsigned long start, unsigned long n, const char *name)
117 {
118     #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
119         if(check_region(start,n)) return 0;
120         request_region(start,n,name);
121         return 1;
122     #else
123         return (request_region(start,n,name))?1:0;
124     #endif
125 }
126
127 void can_release_io_region(unsigned long start, unsigned long n)
128 {
129         release_region(start,n);
130 }
131
132 int can_request_mem_region(unsigned long start, unsigned long n, const char *name)
133 {
134     #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
135         return 1;
136     #else
137         return (request_mem_region(start,n,name))?1:0;
138     #endif
139 }
140
141 void can_release_mem_region(unsigned long start, unsigned long n)
142 {
143     #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
144         return;
145     #else
146         release_mem_region(start,n);
147     #endif
148 }
149
150 /* This function shifts all base address structures acording to address
151    translation between physical and virtual address mappings */
152 int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base)
153 {
154         unsigned long offs;
155         int i, j;
156         
157         offs=new_base-candev->dev_base_addr;
158         candev->dev_base_addr=new_base;
159         for(i=0;i<candev->nr_all_chips;i++){
160                 candev->chip[i]->chip_base_addr += offs;
161                 for(j=0;j<candev->chip[i]->max_objects;j++)
162                         candev->chip[i]->msgobj[j]->obj_base_addr += offs;
163         }
164         return 0;
165 }
166
167 /* The function init_hw_struct is used to initialize the hardware structure. */
168 int init_hw_struct(void)
169 {
170         int i=0;
171
172         hardware_p->nr_boards=0;
173         while ( (hw[i] != NULL) & (i < MAX_HW_CARDS) ) {
174                 hardware_p->nr_boards++;
175
176                 if (init_device_struct(i)) {
177                         CANMSG("Error initializing candevice_t structures.\n");
178                         return -ENODEV;
179                 }
180                 i++;
181         }
182
183         return 0;
184 }
185
186 /* The function init_device_struct is used to initialize a single device 
187  * structure.
188  */
189 int init_device_struct(int card)
190 {
191         struct candevice_t *candev;
192         
193         candev=(struct candevice_t *)kmalloc(sizeof(struct candevice_t),GFP_KERNEL);
194         if (candev==NULL)
195                 return -ENOMEM;
196         else
197                 if ( add_mem_to_list(candev) )
198                         return -ENOMEM;
199
200         memset(candev, 0, sizeof(struct candevice_t));
201
202         hardware_p->candevice[card]=candev;
203         candev->candev_idx=card;
204
205         candev=candev;
206
207         candev->hwname=hw[card];
208         candev->io_addr=io[card];
209         candev->dev_base_addr=io[card];
210
211         candev->hwspecops=(struct hwspecops_t *)kmalloc(sizeof(struct hwspecops_t),GFP_KERNEL);
212         if (candev->hwspecops==NULL)
213                 return -ENOMEM;
214         else
215                 if ( add_mem_to_list(candev->hwspecops) )
216                         return -ENOMEM;
217         memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
218
219         if (init_hwspecops(candev))
220                 return -ENODEV;
221
222         if (candev->hwspecops->init_hw_data(candev))
223                 return -ENODEV;
224
225         if (init_chip_struct(candev))
226                 return -ENODEV;
227
228         return 0;
229 }
230
231 /* The function init_chip_struct is used to initialize all chip_t structures
232  * on one hardware board.
233  */
234 int init_chip_struct(struct candevice_t *candev)
235 {
236         static int irq_count=0;
237         int i=0;
238
239         /* Alocate and initialize the chip structures */
240         for (i=0; i < candev->nr_all_chips; i++) {
241                 candev->chip[i]=(struct chip_t *)kmalloc(sizeof(struct chip_t),GFP_KERNEL);
242                 if (candev->chip[i]==NULL)
243                         return -ENOMEM;
244                 else
245                         if ( add_mem_to_list(candev->chip[i]) )
246                                 return -ENOMEM;
247
248                 memset(candev->chip[i], 0, sizeof(struct chip_t));
249                 
250                 candev->chip[i]->write_register=candev->hwspecops->write_register;
251                 candev->chip[i]->read_register=candev->hwspecops->read_register;
252
253                 candev->chip[i]->chipspecops=(struct chipspecops_t *)kmalloc(sizeof(struct chipspecops_t),GFP_KERNEL);
254                 if (candev->chip[i]->chipspecops==NULL)
255                         return -ENOMEM;
256                 else
257                         if ( add_mem_to_list(candev->chip[i]->chipspecops) )
258                                 return -ENOMEM;
259
260                 chips_p[irq_count]=candev->chip[i];
261                 candev->chip[i]->chip_idx=i;
262                 candev->chip[i]->hostdevice=candev;
263                 candev->chip[i]->chip_irq=irq[irq_count];
264                 candev->chip[i]->flags=0x0;
265
266                 candev->hwspecops->init_chip_data(candev,i);
267
268                 if (init_chipspecops(candev,i))
269                         return -ENODEV;
270
271                 init_obj_struct(candev, candev->chip[i], minor[irq_count]);
272
273                 irq_count++;
274         } 
275
276         return 0;
277 }
278
279 int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase)
280 {
281         struct canque_ends_t *qends;
282         static int obj_count=0;
283         int i,max_objects;
284         struct msgobj_t *obj;
285
286         max_objects=hostchip->max_objects;
287         for (i=0; i<max_objects; i++) {
288                 obj=(struct msgobj_t *)kmalloc(sizeof(struct msgobj_t),GFP_KERNEL);
289                 hostchip->msgobj[i]=obj;
290                 if (obj == NULL) 
291                         return -ENOMEM;
292                 else
293                         if ( add_mem_to_list(obj) )
294                                 return -ENOMEM;
295
296                 memset(obj, 0, sizeof(struct msgobj_t));
297
298                 atomic_set(&obj->obj_used,0);
299                 INIT_LIST_HEAD(&obj->obj_users);
300                 qends = (struct canque_ends_t *)kmalloc(sizeof(struct canque_ends_t), GFP_KERNEL);
301                 if(qends == NULL) return -ENOMEM;
302                 if(add_mem_to_list(qends)) return -ENOMEM;
303                 memset(qends, 0, sizeof(struct canque_ends_t));
304                 obj->hostchip=hostchip;
305                 obj->object=i+1;
306                 obj->qends=qends;
307                 obj->tx_qedge=NULL;
308                 obj->tx_slot=NULL;
309                 obj->flags = 0x0;
310
311                 canqueue_ends_init_chip(qends, hostchip, obj);
312                 
313                 if (minorbase == -1) minorbase=obj_count;
314                 if ((minorbase >= 0) && (minorbase+i<MAX_TOT_MSGOBJS)){
315                   objects_p[minorbase+i]=obj;
316                   obj->minor=minorbase+i;
317                 } else obj->minor=-1;
318
319                 candev->hwspecops->init_obj_data(hostchip,i);
320
321                 obj_count++;
322         }
323         return 0;
324 }
325
326
327 int init_hwspecops(struct candevice_t *candev)
328 {
329         const struct boardtype_t *brp;
330         
331         brp = boardtype_find(candev->hwname);
332         
333         if(!brp) {
334                 CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",candev->hwname);
335                 return -EINVAL;
336         }
337         
338         brp->board_register(candev->hwspecops);
339
340         return 0;
341 }
342
343 int init_chipspecops(struct candevice_t *candev, int chipnr)
344 {
345         if (!strcmp(candev->chip[chipnr]->chip_type,"i82527")) {
346                 candev->chip[chipnr]->max_objects=15;
347                 i82527_register(candev->chip[chipnr]->chipspecops);
348         } 
349         if (!strcmp(candev->chip[chipnr]->chip_type,"sja1000")) {
350                 candev->chip[chipnr]->max_objects=1;
351                 sja1000_register(candev->chip[chipnr]->chipspecops);
352         }
353         if (!strcmp(candev->chip[chipnr]->chip_type,"sja1000p")) {
354                 candev->chip[chipnr]->max_objects=1;
355                 sja1000p_register(candev->chip[chipnr]->chipspecops);
356         }
357
358         return 0;
359 }