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