]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/io/can/v2_0/src/can.c
unified MX27, MX25, MX37 trees
[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_MSG_T   *ptxbuf       = (CYG_CAN_MSG_T *)cbuf->pdata;
240             CYG_CAN_MSG_T   *pbuf_message = &ptxbuf[cbuf->put];
241             cyg_can_message *pmessage     = (cyg_can_message *)_buf;
242             
243             CYG_CAN_WRITE_MSG(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_T *prxbuf     = (CYG_CAN_EVENT_T *)cbuf->pdata;   
290             CYG_CAN_EVENT_T *pbuf_event = &prxbuf[cbuf->get];
291             cyg_can_event *pevent       = (cyg_can_event *)_buf;
292            
293             CYG_CAN_READ_EVENT(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     can_lowlevel_funs  *funs      = chan->funs;
374     
375     switch (key)
376     {
377         //
378         // query about CAN configuration like baud rate
379         //
380         case CYG_IO_GET_CONFIG_CAN_INFO :
381              if (*len < sizeof(cyg_can_info_t)) 
382              {
383                  return -EINVAL;
384              }
385              *pcan_info = chan->config;
386              *len       = sizeof(chan->config);
387              break;
388         //
389         // return rx/tx buffer sizes and counts 
390         //    
391         case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO :
392              {
393                  cyg_can_buf_info_t *pbuf_info;
394                  if (*len < sizeof(cyg_can_buf_info_t))
395                  {
396                      return -EINVAL; 
397                  } 
398           
399                 *len = sizeof(cyg_can_buf_info_t);
400                 pbuf_info = (cyg_can_buf_info_t *)xbuf;
401                 pbuf_info->rx_bufsize = in_cbuf->len;
402                 if (pbuf_info->rx_bufsize)
403                 {
404                     pbuf_info->rx_count = in_cbuf->data_cnt ;
405                 }
406                 else
407                 {
408                     pbuf_info->rx_count = 0;
409                 }            
410                 pbuf_info->tx_bufsize = out_cbuf->len;
411                 if (pbuf_info->tx_bufsize)
412                 {
413                     pbuf_info->tx_count = out_cbuf->data_cnt;
414                 }
415                 else
416                 {
417                     pbuf_info->tx_count = 0;
418                 }
419             }
420             break; // case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
421
422 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS            
423             //
424             // return current timeouts
425             //
426             case CYG_IO_GET_CONFIG_CAN_TIMEOUT :
427                  {
428                      cyg_can_timeout_info_t *ptimeout_info;
429                      if (*len < sizeof(cyg_can_timeout_info_t))
430                      {
431                          return -EINVAL; 
432                      } 
433                      
434                      *len = sizeof(cyg_can_timeout_info_t);
435                       ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
436                       
437                       ptimeout_info->rx_timeout = in_cbuf->timeout;
438                       ptimeout_info->tx_timeout = out_cbuf->timeout;
439                  }
440                  break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
441 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
442
443 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
444             //
445             // check if blocking calls are enabled
446             //
447             case CYG_IO_GET_CONFIG_READ_BLOCKING:
448                  {
449                      if (*len < sizeof(cyg_uint32)) 
450                      {
451                          return -EINVAL;
452                      }
453                      *(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0;
454                  }
455                  break;
456
457             //
458             // check if nonblocking calls are enabled
459             // 
460             case CYG_IO_GET_CONFIG_WRITE_BLOCKING:
461                  {
462                      if (*len < sizeof(cyg_uint32))
463                      {
464                          return -EINVAL;
465                      }
466                      *(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0;
467                  }
468                  break;
469 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
470         
471         //
472         // return hardware description interface
473         //
474         case CYG_IO_GET_CONFIG_CAN_HDI :
475              {
476                  cyg_can_hdi *hdi = (cyg_can_hdi *)xbuf;
477                  if (*len != sizeof(cyg_can_hdi)) 
478                  {
479                      return -EINVAL;
480                  }
481                  hdi = hdi; // avoid compiler warnings
482                  *len = sizeof(cyg_can_hdi);  
483                  //
484                  // pass down to low level to gather more information about
485                  // CAN hardware
486                  //
487                  res = (funs->get_config)(chan, key, xbuf, len); 
488              }
489              break;
490         
491         default:
492             res = (funs->get_config)(chan, key, xbuf, len);
493     } // switch (key)
494     
495     return res;
496 }
497
498
499 //===========================================================================
500 // Set CAN channel configuration
501 //===========================================================================
502 static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, 
503                cyg_uint32      key,
504                const void     *xbuf, 
505                cyg_uint32     *len)
506 {
507     cyg_devtab_entry_t *t         = (cyg_devtab_entry_t *)handle;
508     can_channel        *chan      = (can_channel *)t->priv;
509     Cyg_ErrNo           res       = ENOERR;
510     can_lowlevel_funs  *funs      = chan->funs;
511     can_cbuf_t         *out_cbuf  = &chan->out_cbuf;
512     can_cbuf_t         *in_cbuf   = &chan->in_cbuf;
513     
514     switch (key)
515     {
516 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
517         //
518         // Set calls to read function to blocking / nonblocking mode
519         //
520         case CYG_IO_SET_CONFIG_READ_BLOCKING:
521              {
522                  if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len) 
523                  {
524                      return -EINVAL;
525                  }
526                  in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
527              }
528              break;
529         
530         //
531         // set calls to write functions to blocking / nonblocking mode
532         //     
533         case CYG_IO_SET_CONFIG_WRITE_BLOCKING:
534              {
535                  if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len) 
536                  {
537                      return -EINVAL;
538                  }
539                  out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
540              }
541              break;
542 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
543
544 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS            
545         //
546         // return current timeouts
547         //
548         case CYG_IO_SET_CONFIG_CAN_TIMEOUT :
549              {
550                  cyg_can_timeout_info_t *ptimeout_info;
551                  if (*len < sizeof(cyg_can_timeout_info_t))
552                  {
553                      return -EINVAL; 
554                  } 
555                    
556                  *len = sizeof(cyg_can_timeout_info_t);
557                   ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
558                    
559                   in_cbuf->timeout = ptimeout_info->rx_timeout;
560                   out_cbuf->timeout = ptimeout_info->tx_timeout;
561              }
562              break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
563 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
564
565         case CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
566              {
567                  //
568                  // Flush any buffered input
569                  //
570                  if (in_cbuf->len == 0)
571                  {
572                      break;  // Nothing to do if not buffered
573                  }
574                  cyg_drv_mutex_lock(&in_cbuf->lock);  // Stop any further input processing
575                  cyg_drv_dsr_lock();
576                  if (in_cbuf->waiting) 
577                  {
578                      in_cbuf->abort = true;
579                      cyg_drv_cond_broadcast(&in_cbuf->wait);
580                      in_cbuf->waiting = false;
581                  }
582                  in_cbuf->get = in_cbuf->put = in_cbuf->data_cnt = 0; // Flush buffered input
583                  
584                  //
585                  // Pass to the hardware driver in case it wants to flush FIFOs etc.
586                  //
587                  (funs->set_config)(chan,
588                                     CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH,
589                                     NULL, NULL);
590                  cyg_drv_dsr_unlock();
591                  cyg_drv_mutex_unlock(&in_cbuf->lock);
592             } // CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
593         
594         //
595         // flush any buffered output
596         //    
597         case CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH:
598              {
599                   // Throw away any pending output
600                   if (out_cbuf->len == 0) 
601                   {
602                       break;  // Nothing to do if not buffered
603                   }
604                   cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
605                   cyg_drv_dsr_lock();
606                   if (out_cbuf->data_cnt > 0) 
607                   {
608                       out_cbuf->get = out_cbuf->put = out_cbuf->data_cnt = 0;  // Empties queue!
609                      (funs->stop_xmit)(chan);  // Done with transmit
610                   }
611                   
612                   //
613                   // Pass to the hardware driver in case it wants to flush FIFOs etc.
614                   //
615                   (funs->set_config)(chan,
616                                      CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH,
617                                      NULL, NULL);
618                   if (out_cbuf->waiting) 
619                   {
620                       out_cbuf->abort = true;
621                       cyg_drv_cond_broadcast(&out_cbuf->wait);
622                       out_cbuf->waiting = false;
623                   }// if (out_cbuf->waiting) 
624                   cyg_drv_dsr_unlock();
625                   cyg_drv_mutex_unlock(&out_cbuf->lock);
626               }
627               break; // CYG_IO_GET_CONFIG_CAN_OUTPUT_FLUSH:
628         
629         //
630         // wait until all messages in outbut buffer are sent
631         //      
632         case CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
633              {
634                  // Wait for any pending output to complete
635                  if (out_cbuf->len == 0) 
636                  {
637                      break;  // Nothing to do if not buffered
638                  }
639                  cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
640                  cyg_drv_dsr_lock();
641                  while (out_cbuf->pending || (out_cbuf->data_cnt > 0)) 
642                  {
643                      out_cbuf->waiting = true;
644                      if(!cyg_drv_cond_wait(&out_cbuf->wait))
645                      {
646                          res = -EINTR;
647                      }
648                  }
649                  cyg_drv_dsr_unlock();
650                  cyg_drv_mutex_unlock(&out_cbuf->lock);
651              }
652              break;// CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
653              
654         //     
655         // Abort any outstanding I/O, including blocked reads
656         // Caution - assumed to be called from 'timeout' (i.e. DSR) code  
657         //   
658         case CYG_IO_SET_CONFIG_CAN_ABORT :
659              {
660                  in_cbuf->abort = true;
661                  cyg_drv_cond_broadcast(&in_cbuf->wait);
662                  
663                  out_cbuf->abort = true;
664                  cyg_drv_cond_broadcast(&out_cbuf->wait);
665              }
666              break;
667         
668
669 #ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
670         //
671         // Set callback configuration
672         // To disable callback set flag_mask = 0
673         //
674         case CYG_IO_SET_CONFIG_CAN_CALLBACK:
675              {
676                  if (*len != sizeof(cyg_can_callback_cfg))
677                  {
678                          return -EINVAL;
679                  }
680             
681                  // Copy data under DSR locking
682                  cyg_drv_dsr_lock();
683                  chan->callback_cfg = *((cyg_can_callback_cfg*) xbuf);
684                  cyg_drv_dsr_unlock();
685              }
686              break;
687 #endif //CYGOPT_IO_CAN_SUPPORT_CALLBACK
688
689         default:
690             //
691             // pass down to lower layers
692             //
693             res = (funs->set_config)(chan, key, xbuf, len);
694     } // switch (key)
695     
696     return res;
697 }
698
699
700 //===========================================================================
701 // Select support for CAN channel
702 //===========================================================================
703 static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
704 {
705     //
706     // do nothing here because we currently do not support select
707     //
708     return true;
709 }
710
711
712 //===========================================================================
713 // Callback for received events
714 //===========================================================================
715 static void can_rcv_event(can_channel *chan, void *pdata)
716 {
717     can_cbuf_t       *cbuf   = &chan->in_cbuf;
718     CYG_CAN_EVENT_T  *prxbuf = (CYG_CAN_EVENT_T *)cbuf->pdata;
719 #ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
720     cyg_uint16        flags;
721 #endif
722     
723     //
724     // cbuf is a ring buffer - if the buffer is full, then we overwrite the
725     // oldest message in buffer so the user will always get the actual and
726     // last state of the external hardware that is connected to the
727     // CAN bus. We need to call cyg_drv_dsr_lock() here because this function
728     // may be called from different message box interrupts and so we have to
729     // protect data access here
730     //
731     cyg_drv_dsr_lock();
732     prxbuf[cbuf->put].flags = 0; // clear flags because it is a new event
733     if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata))
734     {
735         if (cbuf->data_cnt < cbuf->len)
736         {
737             cbuf->data_cnt++;
738         }
739         else
740         {
741             //
742             // the buffer is full but a new message arrived. We store this new
743             // message and overwrite the oldest one, but at least we tell the user
744             // that there is an overrun in RX queue
745             //
746             prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
747             cbuf->get = (cbuf->get + 1) % cbuf->len;
748         }
749
750 #ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
751         flags = prxbuf[cbuf->put].flags;
752 #endif
753
754         cbuf->put = (cbuf->put + 1) % cbuf->len;
755         
756         if (cbuf->waiting) 
757         {
758             cbuf->waiting = false;
759             cyg_drv_cond_broadcast(&cbuf->wait);
760         }
761 #ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
762         // Call application callback function, if any of the flag events 
763         // are unmasked.
764         if((flags & chan->callback_cfg.flag_mask) &&
765            (chan->callback_cfg.callback_func))
766         {
767             chan->callback_cfg.callback_func(flags,
768                                              chan->callback_cfg.data);
769         }
770 #endif
771     }
772     
773     cyg_drv_dsr_unlock();
774 }
775
776
777 //===========================================================================
778 // Callback function for transmit events
779 //===========================================================================
780 static void can_xmt_msg(can_channel *chan, void *pdata)
781 {
782     can_cbuf_t        *cbuf    = &chan->out_cbuf;
783     can_lowlevel_funs *funs    = chan->funs;  
784     CYG_CAN_MSG_T     *ptxbuf  = (CYG_CAN_MSG_T *)cbuf->pdata;
785     CYG_CAN_MSG_T     *pbuf_txmsg;
786
787     //
788     // transmit messages as long as there are messages in the buffer 
789     //
790     while (cbuf->data_cnt > 0)
791     {
792         pbuf_txmsg = &ptxbuf[cbuf->get];
793         
794         if (funs->putmsg(chan, pbuf_txmsg, pdata))
795         {
796             cbuf->get = (cbuf->get + 1) % cbuf->len;
797             cbuf->data_cnt--;
798         }
799         else
800         {
801             //
802             // we are here because the hardware is busy at the moment and
803             // we can't send another message - now we check if there is already
804             // some space in buffer so we can wakeup the writer
805             //
806             if ((cbuf->len - cbuf->data_cnt) > 0)
807             {
808                 if (cbuf->waiting)
809                 {
810                     cbuf->waiting = false;
811                     cyg_drv_cond_broadcast(&cbuf->wait);
812                 }
813             }
814             return;
815         }
816     } // while (cbuf->data_cnt > 0)
817     funs->stop_xmit(chan);  // Done with transmit
818     
819     if (cbuf->waiting)
820     {
821         cbuf->waiting = false;
822         cyg_drv_cond_broadcast(&cbuf->wait);
823     }            
824 }
825
826
827 //---------------------------------------------------------------------------
828 // end of can.c