]> rtime.felk.cvut.cz Git - lincan.git/blob - embedded/app/usbcan/setup.c
USBCAN converter code updated to match full version of LinCAN sources.
[lincan.git] / embedded / app / usbcan / setup.c
1 /**************************************************************************/
2 /* File: setup.c - CAN driver and chips setup code                        */
3 /*                                                                        */
4 /* LinCAN - (Not only) Linux CAN bus driver                               */
5 /* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
6 /* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz>             */
7 /* Funded by OCERA and FRESCOR IST projects                               */
8 /* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
9 /*                                                                        */
10 /* LinCAN is free software; you can redistribute it and/or modify it      */
11 /* under terms of the GNU General Public License as published by the      */
12 /* Free Software Foundation; either version 2, or (at your option) any    */
13 /* later version.  LinCAN is distributed in the hope that it will be      */
14 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
15 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
16 /* General Public License for more details. You should have received a    */
17 /* copy of the GNU General Public License along with LinCAN; see file     */
18 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
19 /* Cambridge, MA 02139, USA.                                              */
20 /*                                                                        */
21 /* To allow use of LinCAN in the compact embedded systems firmware        */
22 /* and RT-executives (RTEMS for example), main authors agree with next    */
23 /* special exception:                                                     */
24 /*                                                                        */
25 /* Including LinCAN header files in a file, instantiating LinCAN generics */
26 /* or templates, or linking other files with LinCAN objects to produce    */
27 /* an application image/executable, does not by itself cause the          */
28 /* resulting application image/executable to be covered by                */
29 /* the GNU General Public License.                                        */
30 /* This exception does not however invalidate any other reasons           */
31 /* why the executable file might be covered by the GNU Public License.    */
32 /* Publication of enhanced or derived LinCAN files is required although.  */
33 /**************************************************************************/
34
35 #include "./can/can.h"
36 #include "./can/can_sysdep.h"
37 #include "./can/main.h"
38 #include "./can/devcommon.h"
39 #include "./can/setup.h"
40 //#include "./can/finish.h"
41
42 int init_hwspecops(struct candevice_t *candev, int *irqnum_p);
43 int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p);
44 int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate, long clock);
45 int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int objnr);
46
47 /**
48  * can_base_addr_fixup - relocates board physical memory addresses to the CPU accessible ones
49  * @candev: pointer to the previously filled device/board, chips and message objects structures
50  * @new_base: @candev new base address
51  *
52  * This function adapts base addresses of all structures of one board
53  * to the new board base address.
54  * It is required for translation between physical and virtual address mappings.
55  * This function is prepared to simplify board specific xxx_request_io() function
56  * for memory mapped devices.
57  */
58 int can_base_addr_fixup(struct candevice_t *candev, can_ioptr_t new_base)
59 {
60         long offs;
61         int i, j;
62
63         offs=new_base-candev->dev_base_addr;
64         candev->dev_base_addr=new_base;
65         for(i=0;i<candev->nr_all_chips;i++){
66                 candev->chip[i]->chip_base_addr += offs;
67                 for(j=0;j<candev->chip[i]->max_objects;j++)
68                         candev->chip[i]->msgobj[j]->obj_base_addr += offs;
69         }
70         return 0;
71 }
72
73 /**
74  * can_check_dev_taken - checks if bus device description is already taken by driver
75  * @anydev:     pointer to bus specific Linux device description
76  *
77  * Returns: Returns 1 if device is already used by LinCAN driver, 0 otherwise.
78  */
79 int can_check_dev_taken(void *anydev)
80 {
81         int board_nr;
82         struct candevice_t *candev;
83         void *boarddev;
84
85         for (board_nr=hardware_p->nr_boards; board_nr--; ) {
86                 if((candev=hardware_p->candevice[board_nr])==NULL)
87                         continue;
88                 boarddev=candev->sysdevptr.anydev;
89                 if(boarddev == anydev)
90                         return 1;
91         }
92
93         return 0;
94 }
95
96
97 /**
98  * register_obj_struct - registers message object into global array
99  * @obj: the initialized message object being registered
100  * @minorbase: wanted minor number, if (-1) automatically selected
101  *
102  * Return Value: returns negative number in the case of fail
103  */
104 int register_obj_struct(struct msgobj_t *obj, int minorbase)
105 {
106         static int next_minor=0;
107         int i;
108
109         if(minorbase>=0)
110                 next_minor=minorbase;
111         if(next_minor>=MAX_TOT_MSGOBJS)
112                 next_minor=0;
113         i=next_minor;
114         do{
115                 if(objects_p[i]==NULL){
116                         objects_p[i]=obj;
117                         obj->minor=i;
118                         next_minor=i+1;
119                         return 0;
120                 }
121                 if(++i >= MAX_TOT_MSGOBJS) i=0;
122         }while(i!=next_minor);
123         obj->minor=-1;
124         return -1;
125 }
126
127
128 /**
129  * register_chip_struct - registers chip into global array
130  * @chip: the initialized chip structure being registered
131  * @minorbase: wanted minor number base, if (-1) automatically selected
132  *
133  * Return Value: returns negative number in the case of fail
134  */
135 int register_chip_struct(struct canchip_t *chip, int minorbase)
136 {
137         static int next_chip_slot=0;
138         int i;
139
140         if(next_chip_slot>=MAX_TOT_CHIPS)
141                 next_chip_slot=0;
142         i=next_chip_slot;
143         do{
144                 if(chips_p[i]==NULL){
145                         chips_p[i]=chip;
146
147                         next_chip_slot=i+1;
148                         return 0;
149                 }
150                 if(++i >= MAX_TOT_CHIPS) i=0;
151         }while(i!=next_chip_slot);
152         return -1;
153 }
154
155
156
157 /**
158  * init_hw_struct - initializes driver hardware description structures
159  *
160  * The function init_hw_struct() is used to initialize the hardware structure.
161  *
162  * Return Value: returns negative number in the case of fail
163  */
164 // int init_hw_struct(void)
165 // {
166 //      int i=0;
167 //      int irq_param_idx=0;
168 //      int chan_param_idx=0;
169 //
170 //      hardware_p->nr_boards=0;
171 //      while ( (hw[i] != NULL) & (i < MAX_HW_CARDS) ) {
172 //              hardware_p->nr_boards++;
173 //
174 //              if (init_device_struct(i, &chan_param_idx, &irq_param_idx)) {
175 //                      CANMSG("Error initializing candevice_t structures.\n");
176 //                      return -ENODEV;
177 //              }
178 //              i++;
179 //      }
180 //
181 //      return 0;
182 // }
183
184 /**
185  * init_device_struct - initializes single CAN device/board
186  * @card: index into @hardware_p HW description
187  * @chan_param_idx_p: pointer to the index into arrays of the CAN channel parameters
188  * @irq_param_idx_p: pointer to the index into arrays of the per CAN channel IRQ parameters
189  *
190  * The function builds representation of the one board from parameters provided
191  * in the module parameters arrays:
192  *      @hw[card] .. hardware type,
193  *      @io[card] .. base IO address,
194  *      @baudrate[chan_param_idx] .. per channel baudrate,
195  *      @minor[chan_param_idx] .. optional specification of requested channel minor base,
196  *      @irq[irq_param_idx] .. one or more board/chips IRQ parameters.
197  * The indexes are advanced after consumed parameters if the registration is successful.
198  *
199  * The hardware specific operations of the device/board are initialized by call to
200  * init_hwspecops() function. Then board data are initialized by board specific
201  * init_hw_data() function. Then chips and objects representation is build by
202  * init_chip_struct() function. If all above steps are successful, chips and
203  * message objects are registered into global arrays.
204  *
205  * Return Value: returns negative number in the case of fail
206  */
207 // int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p)
208 // {
209 //      struct candevice_t *candev;
210 //      int ret;
211 //      int irqnum;
212 //      int chipnr;
213 //      long bd;
214 //      int irqsig=-1;
215 //
216 //      candev=(struct candevice_t *)malloc(sizeof(struct candevice_t));
217 //      if (candev==NULL)
218 //              return -ENOMEM;
219 //
220 //         memset(candev, 0, sizeof(struct candevice_t));
221 //
222 //      hardware_p->candevice[card]=candev;
223 //      candev->candev_idx=card;
224 //
225 //      candev=candev;
226 //
227 //      candev->hwname=hw[card];
228 //      candev->io_addr=io[card];
229 //      candev->dev_base_addr=io[card];
230 //
231 //      candev->hwspecops=(struct hwspecops_t *)malloc(sizeof(struct hwspecops_t));
232 //      if (candev->hwspecops==NULL)
233 //              goto error_nomem;
234 //
235 //      memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
236 //
237 //      if (init_hwspecops(candev, &irqnum))
238 //              goto error_nodev;
239 //
240 //      if (candev->hwspecops->init_hw_data(candev))
241 //              goto error_nodev;
242 //
243 //      /* Alocate and initialize the chip structures */
244 //      for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
245 //
246 //              if(chipnr<irqnum)
247 //                      irqsig=irq[*irq_param_idx_p+chipnr];
248 //
249 //              bd=baudrate[*chan_param_idx_p+chipnr];
250 //              if(!bd) bd=baudrate[0];
251 //
252 //              if ((ret=init_chip_struct(candev, chipnr, irqsig, bd*1000)))
253 //                      goto error_chip;
254 //      }
255 //
256 //
257 //
258 //      for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
259 //              int m=minor[*chan_param_idx_p+chipnr];
260 //              struct canchip_t *chip=candev->chip[chipnr];
261 //              int objnr;
262 //
263 //              register_chip_struct(chip, m);
264 //
265 //              for (objnr=0; objnr<chip->max_objects; objnr++) {
266 //                      register_obj_struct(chip->msgobj[objnr], m);
267 //                      if(m>=0) m++;
268 //              }
269 //      }
270 //
271 //      *irq_param_idx_p += irqnum;
272 //      *chan_param_idx_p += candev->nr_all_chips;
273 //
274 //      return 0;
275 //
276 //     error_nodev:
277 //      ret=-ENODEV;
278 //     error_chip:
279 //      candevice_done(candev);
280 //      goto error_both;
281 //
282 //     error_nomem:
283 //      ret=-ENOMEM;
284 //
285 //     error_both:
286 //      hardware_p->candevice[card]=NULL;
287 //      free(candev);
288 //      return ret;
289 //
290 // }
291
292 /**
293  * init_chip_struct - initializes one CAN chip structure
294  * @candev: pointer to the corresponding CAN device/board
295  * @chipnr: index of the chip in the corresponding device/board structure
296  * @irq: chip IRQ number or (-1) if not appropriate
297  * @baudrate: baudrate in the units of 1Bd
298  * @clock: optional chip base clock frequency in 1Hz step
299  *
300  * Chip structure is allocated and chip specific operations are filled by
301  * call to board specific init_chip_data() which calls chip specific
302  * fill_chipspecops(). The message objects are generated by
303  * calls to init_obj_struct() function.
304  *
305  * Return Value: returns negative number in the case of fail
306  */
307 int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate, long clock)
308 {
309         struct canchip_t *chip;
310         int objnr;
311         int ret;
312
313         candev->chip[chipnr]=(struct canchip_t *)malloc(sizeof(struct canchip_t));
314         if ((chip=candev->chip[chipnr])==NULL)
315                 return -ENOMEM;
316
317         memset(chip, 0, sizeof(struct canchip_t));
318
319         chip->write_register=candev->hwspecops->write_register;
320         chip->read_register=candev->hwspecops->read_register;
321
322         chip->chipspecops=malloc(sizeof(struct chipspecops_t));
323         if (chip->chipspecops==NULL)
324                 return -ENOMEM;
325         memset(chip->chipspecops,0,sizeof(struct chipspecops_t));
326
327         chip->chip_idx=chipnr;
328         chip->hostdevice=candev;
329         chip->chip_irq=irq;
330         chip->baudrate=baudrate;
331         chip->clock=clock;
332         chip->flags=0x0;
333
334         if(candev->hwspecops->init_chip_data(candev,chipnr)<0)
335                 return -ENODEV;
336
337         for (objnr=0; objnr<chip->max_objects; objnr++) {
338                 ret=init_obj_struct(candev, chip, objnr);
339                 if(ret<0) return ret;
340         }
341
342         return 0;
343 }
344
345
346 /**
347  * init_obj_struct - initializes one CAN message object structure
348  * @candev: pointer to the corresponding CAN device/board
349  * @hostchip: pointer to the chip containing this object
350  * @objnr: index of the builded object in the chip structure
351  *
352  * The function initializes message object structure and allocates and initializes
353  * CAN queue chip ends structure.
354  *
355  * Return Value: returns negative number in the case of fail
356  */
357 int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int objnr)
358 {
359         struct canque_ends_t *qends;
360         struct msgobj_t *obj;
361         int ret;
362
363         obj=(struct msgobj_t *)malloc(sizeof(struct msgobj_t));
364         hostchip->msgobj[objnr]=obj;
365         if (obj == NULL)
366                 return -ENOMEM;
367
368         memset(obj, 0, sizeof(struct msgobj_t));
369         obj->minor=-1;
370
371         atomic_set(&obj->obj_used,0);
372         INIT_LIST_HEAD(&obj->obj_users);
373 //      init_timer(&obj->tx_timeout);
374
375         qends = (struct canque_ends_t *)malloc(sizeof(struct canque_ends_t));
376         if(qends == NULL) return -ENOMEM;
377         memset(qends, 0, sizeof(struct canque_ends_t));
378         obj->hostchip=hostchip;
379         obj->object=objnr+1;
380         obj->qends=qends;
381         obj->tx_qedge=NULL;
382         obj->tx_slot=NULL;
383         obj->obj_flags = 0x0;
384
385         ret=canqueue_ends_init_chip(qends, hostchip, obj);
386         if(ret<0) return ret;
387
388         ret=candev->hwspecops->init_obj_data(hostchip,objnr);
389         if(ret<0) return ret;
390
391         return 0;
392 }
393
394
395 /**
396  * init_hwspecops - finds and initializes board/device specific operations
397  * @candev: pointer to the corresponding CAN device/board
398  * @irqnum_p: optional pointer to the number of interrupts required by board
399  *
400  * The function searches board @hwname in the list of supported boards types.
401  * The board type specific board_register() function is used to initialize
402  * @hwspecops operations.
403  *
404  * Return Value: returns negative number in the case of fail
405  */
406 // int init_hwspecops(struct candevice_t *candev, int *irqnum_p)
407 // {
408 //      const struct boardtype_t *brp;
409 //
410 //      brp = boardtype_find(candev->hwname);
411 //
412 //      if(!brp) {
413 //              CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",candev->hwname);
414 //              return -EINVAL;
415 //      }
416 //
417 //      if(irqnum_p)
418 //              *irqnum_p=brp->irqnum;
419 //      brp->board_register(candev->hwspecops);
420 //
421 //      return 0;
422 // }