]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/io/can/v2_0/src/can.c
d638a234f3ef54467fbdd8b0e7fdee2f88cce6e5
[karo-tx-redboot.git] / packages / io / can / v2_0 / src / can.c
1 //==========================================================================
2 //
3 //      io/can/common/can.c
4 //
5 //      High level CAN driver
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    Uwe Kindler
45 // Contributors: Uwe Kindler
46 // Date:         2005-05-12
47 // Purpose:      Top level CAN driver
48 // Description: 
49 //
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
54
55 //==========================================================================
56 //                              INCLUDES
57 //==========================================================================
58 #include <pkgconf/io.h>
59 #include <pkgconf/io_can.h>
60
61 #include <cyg/io/io.h>
62 #include <cyg/io/devtab.h>
63 #include <cyg/io/can.h>
64 #include <cyg/infra/cyg_ass.h>      // assertion support
65 #include <cyg/infra/diag.h>         // diagnostic output
66
67
68 //==========================================================================
69 //                                MACROS
70 //==========================================================================
71 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
72 #define CYG_DRV_COND_WAIT(_cond, _time) cyg_cond_timed_wait(_cond, cyg_current_time() + (_time))
73 #else
74 #define CYG_DRV_COND_WAIT(_cond, _time) cyg_drv_cond_wait(_cond)
75 #endif
76
77
78 //==========================================================================
79 //                            LOCAL FUNCTIONS
80 //==========================================================================
81 //
82 // Device I/O functions
83 //
84 static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len);
85 static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len);
86 static cyg_bool  can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);
87 static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf, cyg_uint32 *len);
88 static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf, cyg_uint32 *len);
89
90 //
91 // Callback functions into upper layer driver
92 //
93 static void can_init(can_channel *chan);    
94 static void can_rcv_event(can_channel *chan, void *pdata);
95 static void can_xmt_msg(can_channel *chan, void *pdata);
96
97 //
98 // Device I/O table
99 //
100 DEVIO_TABLE(cyg_io_can_devio,
101             can_write,
102             can_read,
103             can_select,
104             can_get_config,
105             can_set_config
106     );
107
108
109 //
110 // Callbacks into upper layer driver
111 //
112 CAN_CALLBACKS(cyg_io_can_callbacks, 
113               can_init, 
114               can_xmt_msg,
115               can_rcv_event);
116
117
118 //===========================================================================
119 // Initialize CAN driver
120 //===========================================================================
121 static void can_init(can_channel *chan)
122 {
123     can_cbuf_t *cbuf;
124     
125     if (chan->init) 
126     {
127         return;
128     }
129     
130     cbuf = &chan->in_cbuf;
131     cbuf->waiting  = false;
132     cbuf->abort    = false;
133 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
134     cbuf->blocking = true;
135 #endif
136     cyg_drv_mutex_init(&cbuf->lock);
137     cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
138     
139     cbuf = &chan->out_cbuf;
140     cbuf->waiting  = false;
141     cbuf->abort    = false;
142 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
143     cbuf->blocking = true;
144 #endif
145     cyg_drv_mutex_init(&cbuf->lock);
146     cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
147     
148     chan->init = true;
149 }
150
151
152 //===========================================================================
153 // Write exactly one CAN message to CAN bus
154 //===========================================================================
155 static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len)
156 {
157     cyg_devtab_entry_t *t      = (cyg_devtab_entry_t *)handle;
158     can_channel        *chan   = (can_channel *)t->priv;
159     can_lowlevel_funs  *funs   = chan->funs;
160     Cyg_ErrNo           res    = ENOERR;
161     can_cbuf_t         *cbuf   = &chan->out_cbuf;
162     cyg_uint32          size   = *len;
163     
164     //
165     // the user need to provide a can message buffer
166     //
167     if (*len != sizeof(cyg_can_message))
168     {
169         return -EINVAL;
170     }
171     
172     cyg_drv_mutex_lock(&cbuf->lock);
173     cbuf->abort = false;
174     cyg_drv_dsr_lock(); // avoid race condition while testing pointers
175     
176     while (size > 0)
177     {
178         if (cbuf->data_cnt == cbuf->len) 
179         {
180             cbuf->waiting = true;      // Buffer full - wait for space
181             funs->start_xmit(chan);    // Make sure xmit is running
182             //
183             // Check flag: 'start_xmit' may have obviated the need
184             // to wait
185             //
186             if (cbuf->waiting) 
187             {
188                 cbuf->pending += size;  // Have this much more to send [eventually]
189 #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
190 #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
191                 //
192                 // If timeouts are enabled and we use nonblocking calls then we
193                 // can use the timeout values
194                 //
195                 if (!cbuf->blocking)
196                 {
197                     if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
198                     {
199                         cbuf->abort = true;
200                     }
201                 } // if (!cbuf->blocking)#
202                 else
203 #else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
204                 //
205                 // if this is a nonblocking call then we return immediatelly
206                 //
207                 if (!cbuf->blocking)
208                 {
209                     *len = 0;
210                     res = -EAGAIN;
211                     break;
212                 }
213                 else
214 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
215 #endif //defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
216                 {
217                     if(!cyg_drv_cond_wait(&cbuf->wait))
218                     {
219                         cbuf->abort = true;
220                     }
221                 }
222                 cbuf->pending -= size;
223                 if (cbuf->abort) 
224                 {
225                     // Give up!
226                     *len -= size;   // number of characters actually sent
227                      cbuf->abort = false;
228                      cbuf->waiting = false;
229                      res = -EINTR;
230                      break;
231                 } // if (cbuf->abort) 
232             } // if (cbuf->waiting)
233         } // if (cbuf->data_cnt == cbuf->len) 
234         else
235         {           
236             //
237             // there is enougth space left so we can store additional data
238             //
239             cyg_can_message *ptxbuf       = (cyg_can_message *)cbuf->pdata;
240             cyg_can_message *pbuf_message = &ptxbuf[cbuf->put];
241             cyg_can_message *pmessage     = (cyg_can_message *)_buf;
242             
243             *pbuf_message = *pmessage; // copy message
244    
245             cbuf->put = (cbuf->put + 1) % cbuf->len;
246             cbuf->data_cnt++;   
247             size -= sizeof(cyg_can_message);   
248         }
249     } // while (size > 0)
250     
251     (funs->start_xmit)(chan);  // Start output as necessary
252     cyg_drv_dsr_unlock();            
253     cyg_drv_mutex_unlock(&cbuf->lock);
254     return res;
255 }
256
257
258 //===========================================================================
259 // Read one single CAN event from hw
260 //===========================================================================
261 static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
262 {
263     cyg_devtab_entry_t *t      = (cyg_devtab_entry_t *)handle;
264     can_channel        *chan   = (can_channel *)t->priv;
265     can_cbuf_t         *cbuf   = &chan->in_cbuf;
266     cyg_uint32          size   = 0;
267     Cyg_ErrNo           res    = ENOERR;
268     
269     //
270     // the user need to provide a can event buffer
271     //
272     if (*len != sizeof(cyg_can_event))
273     {
274         return -EINVAL;
275     }
276     
277     cyg_drv_mutex_lock(&cbuf->lock);
278     cbuf->abort = false;
279     
280     cyg_drv_dsr_lock();  // avoid race conditions
281     while (size < *len)
282     {
283         //
284         // if message buffer contains at least one message then read the
285         // oldest message from buffer and return
286         //
287         if (cbuf->data_cnt > 0)
288         {
289             cyg_can_event *prxbuf     = (cyg_can_event *)cbuf->pdata;   
290             cyg_can_event *pbuf_event = &prxbuf[cbuf->get];
291             cyg_can_event *pevent     = (cyg_can_event *)_buf;
292
293             *pevent = *pbuf_event; // copy event
294             
295             cbuf->get = (cbuf->get + 1) % cbuf->len;
296             cbuf->data_cnt--; 
297             size += sizeof(cyg_can_event);
298         }
299         else
300         {
301             //
302             // if messaeg buffer does not contain any message, then wait until
303             // a message arrives or return immediatelly if nonblocking calls are
304             // supported
305             //
306             cbuf->waiting = true;
307 #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
308 #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
309             //
310             // If timeouts are enabled and we use nonblocking calls then we
311             // can use the timeout values
312             //
313             if (!cbuf->blocking)
314             {
315                 if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
316                 {
317                     cbuf->abort = true;
318                 }
319             } // if (!cbuf->blocking)#
320             else
321 #else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
322             //
323             // if this is a nonblocking call then we return immediatelly
324             //
325             if (!cbuf->blocking)
326             {
327                 *len = 0;
328                 res = -EAGAIN;
329                 break;
330             }
331             else
332 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
333 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
334             {
335                 if(!cyg_drv_cond_wait(&cbuf->wait))
336                 {
337                     cbuf->abort = true;
338                 }
339             }
340             
341             if (cbuf->abort)
342             {
343                 *len = size;
344                 cbuf->abort = false;
345                 cbuf->waiting = false;
346                 res = -EINTR;
347                 break;
348             }
349         }
350     } // while (size < *len)
351     cyg_drv_dsr_unlock();
352     
353     cyg_drv_mutex_unlock(&cbuf->lock);
354     
355     return res;
356 }
357
358
359 //===========================================================================
360 // Query CAN channel configuration data
361 //===========================================================================
362 static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, 
363                cyg_uint32      key, 
364                void           *xbuf,
365                cyg_uint32     *len)
366 {
367     cyg_devtab_entry_t *t         = (cyg_devtab_entry_t *)handle;
368     can_channel        *chan      = (can_channel *)t->priv;
369     Cyg_ErrNo           res       = ENOERR;
370     cyg_can_info_t     *pcan_info = (cyg_can_info_t *)xbuf;
371     can_cbuf_t         *out_cbuf  = &chan->out_cbuf;
372     can_cbuf_t         *in_cbuf   = &chan->in_cbuf;
373     
374     switch (key)
375     {
376         case CYG_IO_GET_CONFIG_CAN_INFO :
377              if (*len < sizeof(cyg_can_info_t)) 
378              {
379                  return -EINVAL;
380              }
381              *pcan_info = chan->config;
382              *len       = sizeof(chan->config);
383              break;
384         //
385         // return rx/tx buffer sizes and counts 
386         //    
387         case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO :
388              {
389                  cyg_can_buf_info_t *pbuf_info;
390                  if (*len < sizeof(cyg_can_buf_info_t))
391                  {
392                      return -EINVAL; 
393                  } 
394           
395                 *len = sizeof(cyg_can_buf_info_t);
396                 pbuf_info = (cyg_can_buf_info_t *)xbuf;
397                 pbuf_info->rx_bufsize = in_cbuf->len;
398                 if (pbuf_info->rx_bufsize)
399                 {
400                     pbuf_info->rx_count = in_cbuf->data_cnt ;
401                 }
402                 else
403                 {
404                     pbuf_info->rx_count = 0;
405                 }            
406                 pbuf_info->tx_bufsize = out_cbuf->len;
407                 if (pbuf_info->tx_bufsize)
408                 {
409                     pbuf_info->tx_count = out_cbuf->data_cnt;
410                 }
411                 else
412                 {
413                     pbuf_info->tx_count = 0;
414                 }
415             }
416             break; // case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
417
418 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS            
419             //
420             // return current timeouts
421             //
422             case CYG_IO_GET_CONFIG_CAN_TIMEOUT :
423                  {
424                      cyg_can_timeout_info_t *ptimeout_info;
425                      if (*len < sizeof(cyg_can_timeout_info_t))
426                      {
427                          return -EINVAL; 
428                      } 
429                      
430                      *len = sizeof(cyg_can_timeout_info_t);
431                       ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
432                       
433                       ptimeout_info->rx_timeout = in_cbuf->timeout;
434                       ptimeout_info->tx_timeout = out_cbuf->timeout;
435                  }
436                  break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
437 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
438
439 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
440             case CYG_IO_GET_CONFIG_READ_BLOCKING:
441                  {
442                      if (*len < sizeof(cyg_uint32)) 
443                      {
444                          return -EINVAL;
445                      }
446                      *(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0;
447                  }
448                  break;
449
450             case CYG_IO_GET_CONFIG_WRITE_BLOCKING:
451                  {
452                      if (*len < sizeof(cyg_uint32))
453                      {
454                          return -EINVAL;
455                      }
456                      *(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0;
457                  }
458                  break;
459 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
460         
461         default:
462             res = -EINVAL;   
463     } // switch (key)
464     
465     return res;
466 }
467
468
469 //===========================================================================
470 // Set CAN channel configuration
471 //===========================================================================
472 static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, 
473                cyg_uint32      key,
474                const void     *xbuf, 
475                cyg_uint32     *len)
476 {
477     cyg_devtab_entry_t *t         = (cyg_devtab_entry_t *)handle;
478     can_channel        *chan      = (can_channel *)t->priv;
479     Cyg_ErrNo           res       = ENOERR;
480     can_lowlevel_funs  *funs      = chan->funs;
481     can_cbuf_t         *out_cbuf  = &chan->out_cbuf;
482     can_cbuf_t         *in_cbuf   = &chan->in_cbuf;
483     
484     switch (key)
485     {
486 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
487         case CYG_IO_SET_CONFIG_READ_BLOCKING:
488              {
489                  if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len) 
490                  {
491                      return -EINVAL;
492                  }
493                  in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
494              }
495              break;
496              
497         case CYG_IO_SET_CONFIG_WRITE_BLOCKING:
498              {
499                  if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len) 
500                  {
501                      return -EINVAL;
502                  }
503                  out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
504              }
505              break;
506 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
507
508 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS            
509         //
510         // return current timeouts
511         //
512         case CYG_IO_SET_CONFIG_CAN_TIMEOUT :
513              {
514                  cyg_can_timeout_info_t *ptimeout_info;
515                  if (*len < sizeof(cyg_can_timeout_info_t))
516                  {
517                      return -EINVAL; 
518                  } 
519                    
520                  *len = sizeof(cyg_can_timeout_info_t);
521                   ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
522                    
523                   in_cbuf->timeout = ptimeout_info->rx_timeout;
524                   out_cbuf->timeout = ptimeout_info->tx_timeout;
525              }
526              break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
527 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
528         
529         default:
530             //
531             // pass down to lower layers
532             //
533             res = (funs->set_config)(chan, key, xbuf, len);
534     } // switch (key)
535     
536     return res;
537 }
538
539
540 //===========================================================================
541 // Select support for CAN channel
542 //===========================================================================
543 static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
544 {
545     //
546     // do nothing here because we currently do not support select
547     //
548     return true;
549 }
550
551
552 //===========================================================================
553 // Callback for received events
554 //===========================================================================
555 static void can_rcv_event(can_channel *chan, void *pdata)
556 {
557     can_cbuf_t     *cbuf   = &chan->in_cbuf;
558     cyg_can_event  *prxbuf = (cyg_can_event *)cbuf->pdata;
559     
560     //
561     // cbuf is a ring buffer - if the buffer is full, then we overwrite the
562     // oldest message in buffer so the user will always get the actual and
563     // last state of the external hardware that is connected to the
564     // CAN bus. 
565     //
566     if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata))
567     {
568         if (cbuf->data_cnt < cbuf->len)
569         {
570             cbuf->data_cnt++;
571         }
572         else
573         {
574             //
575             // the buffer is full but a new message arrived. We store this new
576             // message and overwrite the oldest one, but at least we tell the user
577             // that there is an overrun in RX queue
578             //
579             prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
580             cbuf->get = (cbuf->get + 1) % cbuf->len;
581         }
582         
583         cbuf->put = (cbuf->put + 1) % cbuf->len;
584         
585         if (cbuf->waiting) 
586         {
587             cbuf->waiting = false;
588             cyg_drv_cond_broadcast(&cbuf->wait);
589         }
590     }
591 }
592
593
594 //===========================================================================
595 // Callback function for transmit events
596 //===========================================================================
597 static void can_xmt_msg(can_channel *chan, void *pdata)
598 {
599     can_cbuf_t        *cbuf    = &chan->out_cbuf;
600     can_lowlevel_funs *funs    = chan->funs;  
601     cyg_can_message   *ptxbuf  = (cyg_can_message *)cbuf->pdata;
602     cyg_can_message   *pbuf_txmsg;
603
604     //
605     // transmit messages as long as there are messages in the buffer 
606     //
607     while (cbuf->data_cnt > 0)
608     {
609         pbuf_txmsg = &ptxbuf[cbuf->get];
610         
611         if (funs->putmsg(chan, pbuf_txmsg, pdata))
612         {
613             cbuf->get = (cbuf->get + 1) % cbuf->len;
614             cbuf->data_cnt--;
615         }
616         else
617         {
618             //
619             // we are here because the hardware is busy at the moment and
620             // we can't send another message - now we check if there is already
621             // some space in buffer so we can wakeup the writer
622             //
623             if ((cbuf->len - cbuf->data_cnt) > 0)
624             {
625                 if (cbuf->waiting)
626                 {
627                     cbuf->waiting = false;
628                     cyg_drv_cond_broadcast(&cbuf->wait);
629                 }
630             }
631             return;
632         }
633     } // while (cbuf->data_cnt > 0)
634     funs->stop_xmit(chan);  // Done with transmit
635     
636     if (cbuf->waiting)
637     {
638         cbuf->waiting = false;
639         cyg_drv_cond_broadcast(&cbuf->wait);
640     }            
641 }
642
643
644 //---------------------------------------------------------------------------
645 // end of can.c