1 //==========================================================================
5 // High level CAN driver
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
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.
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
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.
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.
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.
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####
44 // Author(s): Uwe Kindler
45 // Contributors: Uwe Kindler
47 // Purpose: Top level CAN driver
50 //####DESCRIPTIONEND####
52 //==========================================================================
55 //==========================================================================
57 //==========================================================================
58 #include <pkgconf/io.h>
59 #include <pkgconf/io_can.h>
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
68 //==========================================================================
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))
74 #define CYG_DRV_COND_WAIT(_cond, _time) cyg_drv_cond_wait(_cond)
78 //==========================================================================
80 //==========================================================================
82 // Device I/O functions
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);
91 // Callback functions into upper layer driver
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);
100 DEVIO_TABLE(cyg_io_can_devio,
110 // Callbacks into upper layer driver
112 CAN_CALLBACKS(cyg_io_can_callbacks,
118 //===========================================================================
119 // Initialize CAN driver
120 //===========================================================================
121 static void can_init(can_channel *chan)
130 cbuf = &chan->in_cbuf;
131 cbuf->waiting = false;
133 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
134 cbuf->blocking = true;
136 cyg_drv_mutex_init(&cbuf->lock);
137 cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
139 cbuf = &chan->out_cbuf;
140 cbuf->waiting = false;
142 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
143 cbuf->blocking = true;
145 cyg_drv_mutex_init(&cbuf->lock);
146 cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
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)
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;
165 // the user need to provide a can message buffer
167 if (*len != sizeof(cyg_can_message))
172 cyg_drv_mutex_lock(&cbuf->lock);
174 cyg_drv_dsr_lock(); // avoid race condition while testing pointers
178 if (cbuf->data_cnt == cbuf->len)
180 cbuf->waiting = true; // Buffer full - wait for space
181 funs->start_xmit(chan); // Make sure xmit is running
183 // Check flag: 'start_xmit' may have obviated the need
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)
192 // If timeouts are enabled and we use nonblocking calls then we
193 // can use the timeout values
197 if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
201 } // if (!cbuf->blocking)#
203 #else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
205 // if this is a nonblocking call then we return immediatelly
214 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
215 #endif //defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
217 if(!cyg_drv_cond_wait(&cbuf->wait))
222 cbuf->pending -= size;
226 *len -= size; // number of characters actually sent
228 cbuf->waiting = false;
231 } // if (cbuf->abort)
232 } // if (cbuf->waiting)
233 } // if (cbuf->data_cnt == cbuf->len)
237 // there is enougth space left so we can store additional data
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;
243 *pbuf_message = *pmessage; // copy message
245 cbuf->put = (cbuf->put + 1) % cbuf->len;
247 size -= sizeof(cyg_can_message);
249 } // while (size > 0)
251 (funs->start_xmit)(chan); // Start output as necessary
252 cyg_drv_dsr_unlock();
253 cyg_drv_mutex_unlock(&cbuf->lock);
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)
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;
267 Cyg_ErrNo res = ENOERR;
270 // the user need to provide a can event buffer
272 if (*len != sizeof(cyg_can_event))
277 cyg_drv_mutex_lock(&cbuf->lock);
280 cyg_drv_dsr_lock(); // avoid race conditions
284 // if message buffer contains at least one message then read the
285 // oldest message from buffer and return
287 if (cbuf->data_cnt > 0)
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;
293 *pevent = *pbuf_event; // copy event
295 cbuf->get = (cbuf->get + 1) % cbuf->len;
297 size += sizeof(cyg_can_event);
302 // if messaeg buffer does not contain any message, then wait until
303 // a message arrives or return immediatelly if nonblocking calls are
306 cbuf->waiting = true;
307 #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
308 #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
310 // If timeouts are enabled and we use nonblocking calls then we
311 // can use the timeout values
315 if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
319 } // if (!cbuf->blocking)#
321 #else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
323 // if this is a nonblocking call then we return immediatelly
332 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
333 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
335 if(!cyg_drv_cond_wait(&cbuf->wait))
345 cbuf->waiting = false;
350 } // while (size < *len)
351 cyg_drv_dsr_unlock();
353 cyg_drv_mutex_unlock(&cbuf->lock);
359 //===========================================================================
360 // Query CAN channel configuration data
361 //===========================================================================
362 static Cyg_ErrNo can_get_config(cyg_io_handle_t handle,
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;
376 case CYG_IO_GET_CONFIG_CAN_INFO :
377 if (*len < sizeof(cyg_can_info_t))
381 *pcan_info = chan->config;
382 *len = sizeof(chan->config);
385 // return rx/tx buffer sizes and counts
387 case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO :
389 cyg_can_buf_info_t *pbuf_info;
390 if (*len < sizeof(cyg_can_buf_info_t))
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)
400 pbuf_info->rx_count = in_cbuf->data_cnt ;
404 pbuf_info->rx_count = 0;
406 pbuf_info->tx_bufsize = out_cbuf->len;
407 if (pbuf_info->tx_bufsize)
409 pbuf_info->tx_count = out_cbuf->data_cnt;
413 pbuf_info->tx_count = 0;
416 break; // case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
418 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
420 // return current timeouts
422 case CYG_IO_GET_CONFIG_CAN_TIMEOUT :
424 cyg_can_timeout_info_t *ptimeout_info;
425 if (*len < sizeof(cyg_can_timeout_info_t))
430 *len = sizeof(cyg_can_timeout_info_t);
431 ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
433 ptimeout_info->rx_timeout = in_cbuf->timeout;
434 ptimeout_info->tx_timeout = out_cbuf->timeout;
436 break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
437 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
439 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
440 case CYG_IO_GET_CONFIG_READ_BLOCKING:
442 if (*len < sizeof(cyg_uint32))
446 *(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0;
450 case CYG_IO_GET_CONFIG_WRITE_BLOCKING:
452 if (*len < sizeof(cyg_uint32))
456 *(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0;
459 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
469 //===========================================================================
470 // Set CAN channel configuration
471 //===========================================================================
472 static Cyg_ErrNo can_set_config(cyg_io_handle_t handle,
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;
486 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
487 case CYG_IO_SET_CONFIG_READ_BLOCKING:
489 if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len)
493 in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
497 case CYG_IO_SET_CONFIG_WRITE_BLOCKING:
499 if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len)
503 out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
506 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
508 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
510 // return current timeouts
512 case CYG_IO_SET_CONFIG_CAN_TIMEOUT :
514 cyg_can_timeout_info_t *ptimeout_info;
515 if (*len < sizeof(cyg_can_timeout_info_t))
520 *len = sizeof(cyg_can_timeout_info_t);
521 ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
523 in_cbuf->timeout = ptimeout_info->rx_timeout;
524 out_cbuf->timeout = ptimeout_info->tx_timeout;
526 break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
527 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
531 // pass down to lower layers
533 res = (funs->set_config)(chan, key, xbuf, len);
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)
546 // do nothing here because we currently do not support select
552 //===========================================================================
553 // Callback for received events
554 //===========================================================================
555 static void can_rcv_event(can_channel *chan, void *pdata)
557 can_cbuf_t *cbuf = &chan->in_cbuf;
558 cyg_can_event *prxbuf = (cyg_can_event *)cbuf->pdata;
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
566 if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata))
568 if (cbuf->data_cnt < cbuf->len)
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
579 prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
580 cbuf->get = (cbuf->get + 1) % cbuf->len;
583 cbuf->put = (cbuf->put + 1) % cbuf->len;
587 cbuf->waiting = false;
588 cyg_drv_cond_broadcast(&cbuf->wait);
594 //===========================================================================
595 // Callback function for transmit events
596 //===========================================================================
597 static void can_xmt_msg(can_channel *chan, void *pdata)
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;
605 // transmit messages as long as there are messages in the buffer
607 while (cbuf->data_cnt > 0)
609 pbuf_txmsg = &ptxbuf[cbuf->get];
611 if (funs->putmsg(chan, pbuf_txmsg, pdata))
613 cbuf->get = (cbuf->get + 1) % cbuf->len;
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
623 if ((cbuf->len - cbuf->data_cnt) > 0)
627 cbuf->waiting = false;
628 cyg_drv_cond_broadcast(&cbuf->wait);
633 } // while (cbuf->data_cnt > 0)
634 funs->stop_xmit(chan); // Done with transmit
638 cbuf->waiting = false;
639 cyg_drv_cond_broadcast(&cbuf->wait);
644 //---------------------------------------------------------------------------