This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
I/O CAN driver and MCF52xx FlexCAN device driver
- From: Uwe Kindler <uwe_kindler at web dot de>
- To: ecos-patches at sources dot redhat dot com
- Date: Thu, 26 May 2005 23:03:50 +0200
- Subject: I/O CAN driver and MCF52xx FlexCAN device driver
Hello,
the following patch adds generic I/O CAN driver and MCF52xx FlexCAN
device driver to eCos.
The MCF52xx FlexCAN driver was developed for the SSV/DNP5280 board,
which is not part of the public repository but the driver should also
work with public MCF52xx boards if they provide the necessary defines.
Uwe Kindler
uwe_kindler@web.de
uwe.kindler@cetoni.de
http://www.cetoni.de
diff -urN ecos_web_cvs/ecos/packages/io/can/current/ChangeLog ecos/ecos/packages/io/can/current/ChangeLog
--- ecos_web_cvs/ecos/packages/io/can/current/ChangeLog 1970-01-01 01:00:00.000000000 +0100
+++ ecos/ecos/packages/io/can/current/ChangeLog 2005-05-24 20:06:56.000000000 +0200
@@ -0,0 +1,35 @@
+2005-05-24 Uwe Kindler <uwe_kindler@web.de>
+
+ * Generic CAN driver package created
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003, 2004 eCosCentric Limited
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
diff -urN ecos_web_cvs/ecos/packages/io/can/current/cdl/io_can.cdl ecos/ecos/packages/io/can/current/cdl/io_can.cdl
--- ecos_web_cvs/ecos/packages/io/can/current/cdl/io_can.cdl 1970-01-01 01:00:00.000000000 +0100
+++ ecos/ecos/packages/io/can/current/cdl/io_can.cdl 2005-05-26 21:55:13.000000000 +0200
@@ -0,0 +1,169 @@
+# ====================================================================
+#
+# io_can.cdl
+#
+# eCos IO configuration data
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): Uwe Kindler
+# Original data: gthomas
+# Contributors:
+# Date: 2005-05-17
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_IO_CAN {
+ display "CAN device drivers"
+ active_if CYGPKG_IO
+ requires CYGPKG_ERROR
+ include_dir cyg/io
+ description "
+ This option enables drivers for basic I/O services on
+ CAN devices."
+ doc ref/io.html
+
+ compile -library=libextras.a can.c
+
+ define_proc {
+ puts $::cdl_header "/***** proc output start *****/"
+ puts $::cdl_header "#include <pkgconf/system.h>"
+ puts $::cdl_header "#ifdef CYGDAT_IO_CAN_DEVICE_HEADER"
+ puts $::cdl_header "# include CYGDAT_IO_CAN_DEVICE_HEADER"
+ puts $::cdl_header "#endif "
+ puts $::cdl_header "/****** proc output end ******/"
+ }
+
+ cdl_interface CYGINT_IO_CAN_TIMESTAMP {
+ display "CAN driver supports timestamps"
+ }
+
+ cdl_option CYGOPT_IO_CAN_SUPPORT_TIMESTAMP {
+ display "Support CAN event timestamps"
+ requires { CYGINT_IO_CAN_TIMESTAMP > 0 }
+ default_value 0
+ description "
+ If the CAN hardware driver supports some kind of timestamps
+ then this option enables propagation of timestamps to higher layers.
+ This may add some extra code to hardware drivers."
+ }
+
+ cdl_option CYGOPT_IO_CAN_TX_EVENT_SUPPORT {
+ display "Support TX events"
+ default_value 0
+ description "
+ This option enables support for TX events. If a CAN message is
+ transmitted successfully a TX event will be inserted into the
+ receive event queue and propagated to higher layers. If this
+ option is enabled the RX event queue will be filled faster."
+ }
+
+ cdl_component CYGPKG_IO_CAN_DEVICES {
+ display "Hardware CAN device drivers"
+ flavor bool
+ default_value 1
+ description "
+ This option enables the hardware device drivers
+ for the current platform."
+ }
+
+ cdl_component CYGOPT_IO_CAN_SUPPORT_TIMEOUTS {
+ display "Support read/write timeouts"
+ flavor bool
+ default_value 0
+ active_if CYGPKG_KERNEL
+ requires CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT
+ description "
+ Read and write operations are blocking calls. If no CAN message
+ arrives for a long time the calling thread remains blocked. If the
+ thread should return after a certain amount of time then this
+ option should be enabled."
+
+ cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_READ {
+ display "Default read timeout."
+ flavor data
+ default_value 100
+ description "
+ The initial timeout value in clock ticks for cyg_io_read() calls."
+ }
+
+ cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_WRITE {
+ display "Default write timeout."
+ flavor data
+ default_value 100
+ description "
+ The initial timeout value in clock ticks for cyg_io_write() calls."
+ }
+ }
+
+ cdl_component CYGPKG_IO_CAN_OPTIONS {
+ display "CAN device driver build options"
+ flavor none
+ description "
+ Package specific build options including control over
+ compiler flags used only in building this package,
+ and details of which tests are built."
+
+
+ cdl_option CYGPKG_IO_CAN_CFLAGS_ADD {
+ display "Additional compiler flags"
+ flavor data
+ no_define
+ default_value { "" }
+ description "
+ This option modifies the set of compiler flags for
+ building the CAN device drivers. These flags are used in addition
+ to the set of global flags."
+ }
+
+ cdl_option CYGPKG_IO_CAN_CFLAGS_REMOVE {
+ display "Suppressed compiler flags"
+ flavor data
+ no_define
+ default_value { "" }
+ description "
+ This option modifies the set of compiler flags for
+ building the CAN device drivers. These flags are removed from
+ the set of global flags if present."
+ }
+
+ }
+}
+
+# EOF io_can.cdl
diff -urN ecos_web_cvs/ecos/packages/io/can/current/include/can.h ecos/ecos/packages/io/can/current/include/can.h
--- ecos_web_cvs/ecos/packages/io/can/current/include/can.h 1970-01-01 01:00:00.000000000 +0100
+++ ecos/ecos/packages/io/can/current/include/can.h 2005-05-25 15:18:16.000000000 +0200
@@ -0,0 +1,196 @@
+#ifndef CYGONCE_CAN_H
+#define CYGONCE_CAN_H
+// ====================================================================
+//
+// can.h
+//
+// Device I/O
+//
+// ====================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+// ====================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Uwe Kindler
+// Contributors: gthomas
+// Date: 2005-12-05
+// Purpose: Internal interfaces for CAN I/O drivers
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+// ====================================================================
+
+
+//==========================================================================
+// INCLUDES
+//==========================================================================
+#include <pkgconf/system.h>
+#include <pkgconf/io_can.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/io/io.h>
+#include <cyg/io/canio.h>
+#include <cyg/io/devtab.h>
+#include <cyg/hal/drv_api.h>
+
+
+//===========================================================================
+// FORWARD DECLARATIONS
+//===========================================================================
+typedef struct can_channel can_channel;
+typedef struct can_lowlevel_funs can_lowlevel_funs;
+
+
+//===========================================================================
+// DATA TYPES
+//===========================================================================
+
+//---------------------------------------------------------------------------
+// Pointers into uper-level driver which ISRs and DSRs need
+//
+typedef struct
+{
+ void (*can_init)(can_channel *chan); // Initialize the can channel
+ void (*xmt_msg)(can_channel *chan, void *pdata); // transmit one single message
+ void (*rcv_event)(can_channel *chan, void *pdata);// indicate can event occurance
+} can_callbacks_t;
+
+
+#define CAN_CALLBACKS(_l,_init,_xmt_msg,_rcv_event) \
+can_callbacks_t _l = { \
+ _init, \
+ _xmt_msg, \
+ _rcv_event \
+};
+
+extern can_callbacks_t cyg_io_can_callbacks;
+
+
+//---------------------------------------------------------------------------
+// Data buffer for receive and transmit FIFOs
+//
+typedef struct can_cbuf_st
+{
+ void *pdata; // points to data buffer
+ volatile int put;
+ volatile int get;
+ int len;
+ volatile int data_cnt; // count of events or messages currently in buffer
+ cyg_drv_cond_t wait;
+ cyg_drv_mutex_t lock;
+ bool waiting;
+ volatile bool abort; // Set by an outsider to kill processing
+ volatile cyg_int32 pending; // This many bytes waiting to be sent
+#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+ cyg_uint32 timeout; // timeout value for reading data from buffer
+#endif
+} can_cbuf_t;
+
+
+#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+#define _TX_TIMEOUT CYGNUM_IO_CAN_DEFAULT_TIMEOUT_WRITE
+#define _RX_TIMEOUT CYGNUM_IO_CAN_DEFAULT_TIMEOUT_READ
+#define CBUF_INIT(_data, _len, _timeout) \
+ {_data, 0, 0, _len, timeout : _timeout}
+#else
+#define _TX_TIMEOUT 0
+#define _RX_TIMEOUT 0
+#define CBUF_INIT(_data, _len, _timeout) \
+ {_data, 0, 0, _len, }
+#endif // #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+
+
+//---------------------------------------------------------------------------
+// Private data which describes this channel + initialisation macro
+//
+struct can_channel
+{
+ can_lowlevel_funs *funs;
+ can_callbacks_t *callbacks;
+ void *dev_priv; // Whatever is needed by actual device routines
+ cyg_can_info_t config; // Current configuration
+ bool init; // true if driver is already initialized
+ can_cbuf_t out_cbuf; // buffer for transmit can messages
+ can_cbuf_t in_cbuf; // buffer with received can events
+};
+
+
+
+#define CAN_CHANNEL_USING_INTERRUPTS(_l, \
+ _funs, \
+ _dev_priv, \
+ _baud, \
+ _out_buf, _out_buflen, \
+ _in_buf, _in_buflen) \
+can_channel _l = { \
+ &_funs, \
+ &cyg_io_can_callbacks, \
+ &(_dev_priv), \
+ CYG_CAN_INFO_INIT(_baud), \
+ false, \
+ CBUF_INIT(_out_buf, _out_buflen, _TX_TIMEOUT), \
+ CBUF_INIT(_in_buf, _in_buflen, _RX_TIMEOUT) \
+};
+
+
+
+//---------------------------------------------------------------------------
+// Low level interface functions - these functions are required by the generic
+// CAN driver in order to access the low level hardware
+//
+struct can_lowlevel_funs
+{
+ bool (*putmsg)(can_channel *priv, cyg_can_message *pmsg, void *pdata); // send one can message - return true if consumed
+ bool (*getevent)(can_channel *priv, cyg_can_event *pevent, void *pdata); // fetch one CAN event from device
+ Cyg_ErrNo (*set_config)(can_channel *priv, // Change hardware configuration (baud rate, etc)
+ cyg_uint32 key,
+ const void *xbuf,
+ cyg_uint32 *len);
+ void (*start_xmit)(can_channel *priv); // Enable the transmit channel and turn on transmit interrupts
+ void (*stop_xmit)(can_channel *priv); // Disable the transmit channel and turn transmit interrupts off
+};
+
+#define CAN_LOWLEVEL_FUNS(_l,_putmsg,_getevent,_set_config,_start_xmit,_stop_xmit) \
+can_lowlevel_funs _l = { \
+ _putmsg, \
+ _getevent, \
+ _set_config, \
+ _start_xmit, \
+ _stop_xmit \
+};
+
+extern cyg_devio_table_t cyg_io_can_devio;
+//-------------------------------------------------------------------------
+#endif // CYGONCE_SERIAL_H
diff -urN ecos_web_cvs/ecos/packages/io/can/current/include/canio.h ecos/ecos/packages/io/can/current/include/canio.h
--- ecos_web_cvs/ecos/packages/io/can/current/include/canio.h 1970-01-01 01:00:00.000000000 +0100
+++ ecos/ecos/packages/io/can/current/include/canio.h 2005-05-25 15:17:27.000000000 +0200
@@ -0,0 +1,182 @@
+#ifndef CYGONCE_CANIO_H
+#define CYGONCE_CANIO_H
+// ====================================================================
+//
+// canio.h
+//
+// Device I/O
+//
+// ====================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+// ====================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Uwe Kindler
+// Contributors: gthomas
+// Date: 2005-05-12
+// Purpose: Special support for CAN I/O devices
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+// ====================================================================
+
+
+//===========================================================================
+// INCLUDES
+//===========================================================================
+#include <pkgconf/system.h>
+#include <pkgconf/io_can.h>
+#include <pkgconf/hal.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/io/config_keys.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+//===========================================================================
+// DATA TYPES
+//===========================================================================
+
+//
+// Supported baud rates
+//
+typedef enum {
+ CYGNUM_CAN_KBAUD_10 = 1,
+ CYGNUM_CAN_KBAUD_20,
+ CYGNUM_CAN_KBAUD_50,
+ CYGNUM_CAN_KBAUD_100,
+ CYGNUM_CAN_KBAUD_125,
+ CYGNUM_CAN_KBAUD_250,
+ CYGNUM_CAN_KBAUD_500,
+ CYGNUM_CAN_KBAUD_800,
+ CYGNUM_CAN_KBAUD_1000,
+} cyg_can_baud_rate_t;
+#define CYGNUM_CAN_KBAUD_MIN CYGNUM_CAN_KBAUD_10
+#define CYGNUM_CAN_KBAUD_MAX CYGNUM_CAN_KBAUD_1000
+
+
+// Note: two levels of macro are required to get proper expansion.
+#define _CYG_CAN_BAUD_RATE(n) CYGNUM_CAN_KBAUD_##n
+#define CYG_CAN_BAUD_RATE(n) _CYG_CAN_BAUD_RATE(n)
+
+//
+// Event types for received events. Not all event types are supported by each CAN
+// hardware but normally these events should cover the most common CAN events
+// that may occur. A combination of the event type values is allowed.
+//
+typedef enum
+{
+ CYGNUM_CAN_EVENT_RX = 0x0001, // message received
+ CYGNUM_CAN_EVENT_TX = 0x0002, // mesage transmitted
+ CYGNUM_CAN_EVENT_WARNING_RX = 0x0004, // tx error counter (TEC) reached warning level (>96)
+ CYGNUM_CAN_EVENT_WARNING_TX = 0x0008, // rx error counter (REC) reached warning level (>96)
+ CYGNUM_CAN_EVENT_ERR_PASSIVE = 0x0010, // CAN "error passive" occured
+ CYGNUM_CAN_EVENT_BUS_OFF = 0x0020, // CAN "bus off" error occured
+ CYGNUM_CAN_EVENT_OVERRUN_RX = 0x0040, // overrun in RX queue or hardware occured
+ CYGNUM_CAN_EVENT_OVERRUN_TX = 0x0080, // overrun in TX queue occured
+ CYGNUM_CAN_EVENT_CAN_ERR = 0x0100, // a CAN bit or frame error occured
+ CYGNUM_CAN_EVENT_LEAVING_STANDBY = 0x0200, // CAN hardware leaves standby / power don mode or is waked up
+ CYGNUM_CAN_EVENT_ENTERING_STANDBY = 0x0400, // CAN hardware enters standby / power down mode
+ CYGNUM_CAN_EVENT_ARBITRATION_LOST = 0x0800, // arbitration lost
+ CYGNUM_CAN_EVENT_DEVICE_CHANGED = 0x1000, // device changed event
+} cyg_can_event_type;
+
+
+//
+// CAN message type for transport or transmit of CAN messages
+//
+typedef struct can_message
+{
+ cyg_uint32 id;
+ cyg_uint8 data[8];
+ cyg_uint8 ext;
+ cyg_uint8 rtr;
+ cyg_uint8 dlc;
+} cyg_can_message;
+
+//
+// CAN event type for reception of CAN events from driver. CAN events may be
+// a received CAN message or any other status information like tx msg or
+// arbitration lost
+//
+typedef struct cyg_can_event_st
+{
+ cyg_uint32 timestamp;
+ cyg_can_message msg;
+ cyg_uint16 type;
+} cyg_can_event;
+
+//
+// CAN configuration - at the moment there is only one data member but we are
+// prepared for future enhancements
+//
+typedef struct cyg_can_info_st {
+ cyg_can_baud_rate_t baud;
+} cyg_can_info_t;
+
+//
+// buffer configuration - bufsize and count for tx are the number of messages
+// and for rx the number of events
+//
+typedef struct cyg_can_buf_info_st
+{
+ cyg_int32 rx_bufsize;
+ cyg_int32 rx_count;
+ cyg_int32 tx_bufsize;
+ cyg_int32 tx_count;
+} cyg_can_buf_info_t;
+
+//
+// Timeout configuration
+//
+typedef struct cyg_can_timeout_info_st
+{
+ cyg_uint32 rx_timeout;
+ cyg_uint32 tx_timeout;
+} cyg_can_timeout_info_t;
+
+
+#define CYG_CAN_INFO_INIT(_baud) \
+ { _baud}
+
+#ifdef __cplusplus
+}
+#endif
+
+//---------------------------------------------------------------------------
+#endif // CYGONCE_CANIO_H
diff -urN ecos_web_cvs/ecos/packages/io/can/current/src/can.c ecos/ecos/packages/io/can/current/src/can.c
--- ecos_web_cvs/ecos/packages/io/can/current/src/can.c 1970-01-01 01:00:00.000000000 +0100
+++ ecos/ecos/packages/io/can/current/src/can.c 2005-05-26 21:58:02.000000000 +0200
@@ -0,0 +1,532 @@
+//==========================================================================
+//
+// io/can/common/can.c
+//
+// High level CAN driver
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Uwe Kindler
+// Contributors: Uwe Kindler
+// Date: 2005-05-12
+// Purpose: Top level CAN driver
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+
+//==========================================================================
+// INCLUDES
+//==========================================================================
+#include <pkgconf/io.h>
+#include <pkgconf/io_can.h>
+
+#include <cyg/io/io.h>
+#include <cyg/io/devtab.h>
+#include <cyg/io/can.h>
+#include <cyg/infra/cyg_ass.h> // assertion support
+#include <cyg/infra/diag.h> // diagnostic output
+
+
+//==========================================================================
+// MACROS
+//==========================================================================
+#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+#define CYG_DRV_COND_WAIT(_cond, _time) cyg_cond_timed_wait(_cond, cyg_current_time() + (_time))
+#else
+#define CYG_DRV_COND_WAIT(_cond, _time) cyg_drv_cond_wait(_cond)
+#endif
+
+
+//==========================================================================
+// LOCAL FUNCTIONS
+//==========================================================================
+//
+// Device I/O functions
+//
+static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len);
+static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len);
+static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);
+static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf, cyg_uint32 *len);
+static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf, cyg_uint32 *len);
+
+//
+// Callback functions into upper layer driver
+//
+static void can_init(can_channel *chan);
+static void can_rcv_event(can_channel *chan, void *pdata);
+static void can_xmt_msg(can_channel *chan, void *pdata);
+
+//
+// Device I/O table
+//
+DEVIO_TABLE(cyg_io_can_devio,
+ can_write,
+ can_read,
+ can_select,
+ can_get_config,
+ can_set_config
+ );
+
+
+//
+// Callbacks into upper layer driver
+//
+CAN_CALLBACKS(cyg_io_can_callbacks,
+ can_init,
+ can_xmt_msg,
+ can_rcv_event);
+
+
+//===========================================================================
+// Initialize CAN driver
+//===========================================================================
+static void can_init(can_channel *chan)
+{
+ can_cbuf_t *cbuf;
+
+ if (chan->init)
+ {
+ return;
+ }
+
+ cbuf = &chan->in_cbuf;
+ cyg_drv_mutex_init(&cbuf->lock);
+ cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
+
+ cbuf = &chan->out_cbuf;
+ cyg_drv_mutex_init(&cbuf->lock);
+ cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
+
+ chan->init = true;
+}
+
+
+//===========================================================================
+// Write exactly one CAN message to CAN bus
+//===========================================================================
+static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len)
+{
+ cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
+ can_channel *chan = (can_channel *)t->priv;
+ can_lowlevel_funs *funs = chan->funs;
+ Cyg_ErrNo res = ENOERR;
+ can_cbuf_t *cbuf = &chan->out_cbuf;
+ cyg_uint32 size = *len;
+
+ //
+ // the user need to provide a can message buffer
+ //
+ if (*len != sizeof(cyg_can_message))
+ {
+ return -EINVAL;
+ }
+
+ cyg_drv_mutex_lock(&cbuf->lock);
+ cbuf->abort = false;
+ cyg_drv_dsr_lock(); // avoid race condition while testing pointers
+
+ while (size > 0)
+ {
+ if (cbuf->data_cnt == cbuf->len)
+ {
+ cbuf->waiting = true; // Buffer full - wait for space
+ funs->start_xmit(chan); // Make sure xmit is running
+ //
+ // Check flag: 'start_xmit' may have obviated the need
+ // to wait
+ //
+ if (cbuf->waiting)
+ {
+ cbuf->pending += size; // Have this much more to send [eventually]
+ if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
+ {
+ cbuf->abort = true;
+ }
+ cbuf->pending -= size;
+ if (cbuf->abort)
+ {
+ // Give up!
+ *len -= size; // number of characters actually sent
+ cbuf->abort = false;
+ cbuf->waiting = false;
+ res = -EINTR;
+ break;
+ } // if (cbuf->abort)
+ } // if (cbuf->waiting)
+ } // if (cbuf->data_cnt == cbuf->len)
+ else
+ {
+ //
+ // there is enougth space left so we can store additional data
+ //
+ cyg_can_message *ptxbuf = (cyg_can_message *)cbuf->pdata;
+ cyg_can_message *pbuf_message = &ptxbuf[cbuf->put];
+ cyg_can_message *pmessage = (cyg_can_message *)_buf;
+
+ *pbuf_message = *pmessage; // copy message
+
+ cbuf->put = (cbuf->put + 1) % cbuf->len;
+ cbuf->data_cnt++;
+ size -= sizeof(cyg_can_message);
+ }
+ } // while (size > 0)
+
+ (funs->start_xmit)(chan); // Start output as necessary
+ cyg_drv_dsr_unlock();
+ cyg_drv_mutex_unlock(&cbuf->lock);
+ return res;
+}
+
+
+//===========================================================================
+// Read one single CAN event from hw
+//===========================================================================
+static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
+{
+ cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
+ can_channel *chan = (can_channel *)t->priv;
+ can_cbuf_t *cbuf = &chan->in_cbuf;
+ cyg_uint32 size = 0;
+ Cyg_ErrNo res = ENOERR;
+
+ //
+ // the user need to provide a can event buffer
+ //
+ if (*len != sizeof(cyg_can_event))
+ {
+ return -EINVAL;
+ }
+
+ cyg_drv_mutex_lock(&cbuf->lock);
+ cbuf->abort = false;
+
+ cyg_drv_dsr_lock(); // avoid race conditions
+ while (size < *len)
+ {
+ //
+ // if message buffer contains at least one message then read the
+ // oldest message from buffer and return
+ //
+ if (cbuf->data_cnt > 0)
+ {
+ cyg_can_event *prxbuf = (cyg_can_event *)cbuf->pdata;
+ cyg_can_event *pbuf_event = &prxbuf[cbuf->get];
+ cyg_can_event *pevent = (cyg_can_event *)_buf;
+
+ *pevent = *pbuf_event; // copy event
+
+ cbuf->get = (cbuf->get + 1) % cbuf->len;
+ cbuf->data_cnt--;
+ size += sizeof(cyg_can_event);
+ }
+ else
+ {
+ //
+ // if messaeg buffer does not contain any message, then wait until
+ // a message arrives
+ //
+ cbuf->waiting = true;
+ if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
+ {
+ cbuf->abort = true;
+ }
+
+ if (cbuf->abort)
+ {
+ *len = size;
+ cbuf->abort = false;
+ cbuf->waiting = false;
+ res = -EINTR;
+ break;
+ }
+ }
+ } // while (size < *len)
+ cyg_drv_dsr_unlock();
+
+ cyg_drv_mutex_unlock(&cbuf->lock);
+
+ return res;
+}
+
+
+//===========================================================================
+// Query CAN channel configuration data
+//===========================================================================
+static Cyg_ErrNo can_get_config(cyg_io_handle_t handle,
+ cyg_uint32 key,
+ void *xbuf,
+ cyg_uint32 *len)
+{
+ cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
+ can_channel *chan = (can_channel *)t->priv;
+ Cyg_ErrNo res = ENOERR;
+ cyg_can_info_t *pcan_info = (cyg_can_info_t *)xbuf;
+ can_cbuf_t *out_cbuf = &chan->out_cbuf;
+ can_cbuf_t *in_cbuf = &chan->in_cbuf;
+
+ switch (key)
+ {
+ case CYG_IO_GET_CONFIG_CAN_INFO :
+ if (*len < sizeof(cyg_can_info_t))
+ {
+ return -EINVAL;
+ }
+ *pcan_info = chan->config;
+ *len = sizeof(chan->config);
+ break;
+ //
+ // return rx/tx buffer sizes and counts
+ //
+ case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO :
+ {
+ cyg_can_buf_info_t *pbuf_info;
+ if (*len < sizeof(cyg_can_buf_info_t))
+ {
+ return -EINVAL;
+ }
+
+ *len = sizeof(cyg_can_buf_info_t);
+ pbuf_info = (cyg_can_buf_info_t *)xbuf;
+ pbuf_info->rx_bufsize = in_cbuf->len;
+ if (pbuf_info->rx_bufsize)
+ {
+ pbuf_info->rx_count = in_cbuf->data_cnt ;
+ }
+ else
+ {
+ pbuf_info->rx_count = 0;
+ }
+ pbuf_info->tx_bufsize = out_cbuf->len;
+ if (pbuf_info->tx_bufsize)
+ {
+ pbuf_info->tx_count = out_cbuf->data_cnt;
+ }
+ else
+ {
+ pbuf_info->tx_count = 0;
+ }
+ }
+ break; // case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
+
+#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+ //
+ // return current timeouts
+ //
+ case CYG_IO_GET_CONFIG_CAN_TIMEOUT :
+ {
+ cyg_can_timeout_info_t *ptimeout_info;
+ if (*len < sizeof(cyg_can_timeout_info_t))
+ {
+ return -EINVAL;
+ }
+
+ *len = sizeof(cyg_can_timeout_info_t);
+ ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
+
+ ptimeout_info->rx_timeout = in_cbuf->timeout;
+ ptimeout_info->tx_timeout = out_cbuf->timeout;
+ }
+ break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
+#endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+
+ default:
+ res = -EINVAL;
+ } // switch (key)
+
+ return res;
+}
+
+
+//===========================================================================
+// Set CAN channel configuration
+//===========================================================================
+static Cyg_ErrNo can_set_config(cyg_io_handle_t handle,
+ cyg_uint32 key,
+ const void *xbuf,
+ cyg_uint32 *len)
+{
+ cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
+ can_channel *chan = (can_channel *)t->priv;
+ Cyg_ErrNo res = ENOERR;
+ can_lowlevel_funs *funs = chan->funs;
+ can_cbuf_t *out_cbuf = &chan->out_cbuf;
+ can_cbuf_t *in_cbuf = &chan->in_cbuf;
+
+ switch (key)
+ {
+#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+ //
+ // return current timeouts
+ //
+ case CYG_IO_SET_CONFIG_CAN_TIMEOUT :
+ {
+ cyg_can_timeout_info_t *ptimeout_info;
+ if (*len < sizeof(cyg_can_timeout_info_t))
+ {
+ return -EINVAL;
+ }
+
+ *len = sizeof(cyg_can_timeout_info_t);
+ ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
+
+ in_cbuf->timeout = ptimeout_info->rx_timeout;
+ out_cbuf->timeout = ptimeout_info->tx_timeout;
+ }
+ break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
+#endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+
+ default:
+ //
+ // pass down to lower layers
+ //
+ res = (funs->set_config)(chan, key, xbuf, len);
+ } // switch (key)
+
+ return res;
+}
+
+
+//===========================================================================
+// Select support for CAN channel
+//===========================================================================
+static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
+{
+ //
+ // do nothing here because we currently do not support select
+ //
+ return true;
+}
+
+
+//===========================================================================
+// Callback for received events
+//===========================================================================
+static void can_rcv_event(can_channel *chan, void *pdata)
+{
+ can_cbuf_t *cbuf = &chan->in_cbuf;
+ cyg_can_event *prxbuf = (cyg_can_event *)cbuf->pdata;
+
+ //
+ // cbuf is a ring buffer - if the buffer is full, then we overwrite the
+ // oldest message in buffer so the user will always get the actual and
+ // last state of the external hardware that is connected to the
+ // CAN bus.
+ //
+ if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata))
+ {
+ if (cbuf->data_cnt < cbuf->len)
+ {
+ cbuf->data_cnt++;
+ }
+ else
+ {
+ //
+ // the buffer is full but a new message arrived. We store this new
+ // message and overwrite the oldest one, but at least we tell the user
+ // that there is an overrun in RX queue
+ //
+ prxbuf[cbuf->put].type |= CYGNUM_CAN_EVENT_OVERRUN_RX;
+ cbuf->get = (cbuf->get + 1) % cbuf->len;
+ }
+
+ cbuf->put = (cbuf->put + 1) % cbuf->len;
+
+ if (cbuf->waiting)
+ {
+ cbuf->waiting = false;
+ cyg_drv_cond_broadcast(&cbuf->wait);
+ }
+ }
+}
+
+
+//===========================================================================
+// Callback function for transmit events
+//===========================================================================
+static void can_xmt_msg(can_channel *chan, void *pdata)
+{
+ can_cbuf_t *cbuf = &chan->out_cbuf;
+ can_lowlevel_funs *funs = chan->funs;
+ cyg_can_message *ptxbuf = (cyg_can_message *)cbuf->pdata;
+ cyg_can_message *pbuf_txmsg;
+
+ //
+ // transmit messages as long as there are messages in the buffer
+ //
+ while (cbuf->data_cnt > 0)
+ {
+ pbuf_txmsg = &ptxbuf[cbuf->get];
+
+ if (funs->putmsg(chan, pbuf_txmsg, pdata))
+ {
+ cbuf->get = (cbuf->get + 1) % cbuf->len;
+ cbuf->data_cnt--;
+ }
+ else
+ {
+ //
+ // we are here because the hardware is busy at the moment and
+ // we can't send another message - now we check if there is already
+ // some space in buffer so we can wakeup the writer
+ //
+ if ((cbuf->len - cbuf->data_cnt) > 0)
+ {
+ if (cbuf->waiting)
+ {
+ cbuf->waiting = false;
+ cyg_drv_cond_broadcast(&cbuf->wait);
+ }
+ }
+ return;
+ }
+ } // while (cbuf->data_cnt > 0)
+ funs->stop_xmit(chan); // Done with transmit
+
+ if (cbuf->waiting)
+ {
+ cbuf->waiting = false;
+ cyg_drv_cond_broadcast(&cbuf->wait);
+ }
+}
+
+
+//---------------------------------------------------------------------------
+// end of can.c
diff -urN ecos_web_cvs/ecos/packages/devs/can/m68k/mcf52xx/current/ChangeLog ecos/ecos/packages/devs/can/m68k/mcf52xx/current/ChangeLog
--- ecos_web_cvs/ecos/packages/devs/can/m68k/mcf52xx/current/ChangeLog 1970-01-01 01:00:00.000000000 +0100
+++ ecos/ecos/packages/devs/can/m68k/mcf52xx/current/ChangeLog 2005-05-24 20:08:57.000000000 +0200
@@ -0,0 +1,38 @@
+2005-05-24 Uwe Kindler <uwe_kindler@web.de>
+
+ * mcf52xx FlexCAN driver package created
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
diff -urN ecos_web_cvs/ecos/packages/devs/can/m68k/mcf52xx/current/cdl/can_mcf52xx.cdl ecos/ecos/packages/devs/can/m68k/mcf52xx/current/cdl/can_mcf52xx.cdl
--- ecos_web_cvs/ecos/packages/devs/can/m68k/mcf52xx/current/cdl/can_mcf52xx.cdl 1970-01-01 01:00:00.000000000 +0100
+++ ecos/ecos/packages/devs/can/m68k/mcf52xx/current/cdl/can_mcf52xx.cdl 2005-05-24 00:26:15.000000000 +0200
@@ -0,0 +1,331 @@
+# ====================================================================
+#
+# can_mcf52xx.cdl
+#
+# eCos MCF52xx FlexCAN configuration data
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2003, 2004 eCosCentric Limited
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): Uwe Kindler
+# Contributors:
+# Date: 2005-05-17
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+
+
+cdl_package CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN {
+ display "CAN driver for FlexCAN module of coldfire mcf52xx family"
+
+ parent CYGPKG_IO_CAN_DEVICES
+ active_if CYGPKG_IO_CAN
+ active_if CYGPKG_HAL_M68K_MCF52xx
+
+ requires CYGPKG_ERROR
+
+ description "
+ This package provides a generic CAN device driver for the on-chip
+ FlexCAN modules in MCF52xx ColdFire processors."
+ compile -library=libextras.a can_mcf52xx.c
+ define_proc {
+ puts $::cdl_system_header "/***** CAN driver proc output start *****/"
+ puts $::cdl_system_header "#define CYGDAT_IO_CAN_DEVICE_HEADER <pkgconf/devs_can_mcf52xx_flexcan.h>"
+ puts $::cdl_system_header "/***** CAN driver proc output end *****/"
+ }
+
+ # Support up to two on-chip FlexCAN modules. The number varies between
+ # processor variants
+ for { set ::flexcan 0 } { $::flexcan < 2 } { incr ::flexcan } {
+
+ cdl_interface CYGINT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan] {
+ display "Platform provides FlexCAN [set ::flexcan]"
+ flavor bool
+ description "
+ This interface will be implemented if the specific coldfire
+ processor being used has an on-chip FlexCAN[set ::flexcan], and if
+ that FlexCAN is accessible on the target hardware."
+ }
+
+ cdl_component CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan] {
+ display "Allow access to the on-chip FlexCAN[set ::flexcan] via a CAN driver"
+ flavor bool
+ active_if CYGINT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]
+ default_value 1
+ implements CYGINT_IO_CAN_TIMESTAMP
+
+ description "
+ If the application needs to access the on-chip FlexCAN[set ::flexcan]
+ via an eCos CAN driver then this option should be enabled."
+
+ cdl_option CYGDAT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_NAME {
+ display "Device name for FlexCAN [set ::flexcan]"
+ flavor data
+ default_value [format {"\"/dev/can%d\""} $::flexcan]
+ description "
+ This option controls the name that an eCos application
+ should use to access this device via cyg_io_lookup(),
+ open(), or similar calls."
+ }
+
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_KBAUD {
+ display "Default baud rate for FlexCAN [set ::flexcan]"
+ flavor data
+ default_value 100
+ legal_values { 10 20 50 100 125 250 500 800 1000 }
+ description "This option determines the initial baud rate in KBaud for FlexCAN [set ::flexcan]"
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_QUEUESIZE_TX {
+ display "Size of TX Queue for the FlexCAN [set ::flexcan] driver"
+ flavor data
+ default_value 32
+ legal_values 16 to 512
+ description "
+ The CAN device driver will run in interrupt mode and will
+ perform buffering of outgoing data. This option controls the number
+ of CAN messages the TX queue can store."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_QUEUESIZE_RX {
+ display "Size of RX Queue for the FlexCAN [set ::flexcan] driver"
+ flavor data
+ default_value 32
+ legal_values 16 to 512
+ description "
+ The CAN device driver will run in interrupt mode and will
+ perform buffering of incoming data. This option controls the number
+ of CAN events the RX queue can store."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_RXMASK_GLOBAL {
+ display "Receive mask for message buffers 0 - 13"
+ flavor data
+ default_value 0x1FFFFFFF
+ description "
+ The global RX-mask is composed of 4 bytes. The mask bits are
+ applied to all Rx-Identifiers excluding Rx-buffers 14-15, that
+ have their specific Rx-mask. (0 corresponding incoming ID bit is
+ \"don?t care\". 1 corresponding ID bit is checked against the incoming
+ ID bit, to see if a match exists). By default the message buffers
+ should only receive messages that exactly match the configured
+ message buffer CAN identifier - that means alle bits are 1."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_RXMASK_14 {
+ display "Receive mask for message buffer 14"
+ flavor data
+ default_value 0x0
+ description "
+ The RX-mask for message buffer 14 is composed of 4 bytes. The mask
+ bits are applied to message buffer 14. (0 corresponding incoming ID
+ bit is \"don?t care\". 1 corresponding ID bit is checked against the
+ incoming ID bit, to see if a match exists). Message buffer 14 is
+ the receive message buffer and should receive all available CAN
+ messages - all bits are 0."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_RXMASK_15 {
+ display "Receive mask for message buffer 15"
+ flavor data
+ default_value 0x1FFFFFFF
+ description "
+ The RX-mask for message buffer 15 is composed of 4 bytes. The mask
+ bits are applied to message buffer 15. (0 corresponding incoming ID
+ bit is \"don?t care\". 1 corresponding ID bit is checked against the
+ incoming ID bit, to see if a match exists)."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_ISR_PRIORITY_FLEXCAN[set ::flexcan]_WAKEINT {
+ display "Wake interrupt priority"
+ flavor data
+ default_value is_loaded(CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_WAKEINT) ? \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_WAKEINT : \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN
+ legal_values CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN to CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MAX
+ description "
+ Interrupt priority for wake interrupt."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_ISR_PRIORITY_FLEXCAN[set ::flexcan]_ERRINT {
+ display "Error interrupt priority"
+ flavor data
+ default_value is_loaded(CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_ERRINT) ? \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_ERRINT : \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN
+ legal_values CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN to CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MAX
+ description "
+ Interrupt priority for error interrupt."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_ISR_PRIORITY_FLEXCAN[set ::flexcan]_BOFFINT {
+ display "Bus off interrupt priority"
+ flavor data
+ default_value is_loaded(CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_BOFFINT) ? \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_BOFFINT : \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN
+ legal_values CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN to CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MAX
+ description "
+ Interrupt priority for bus off interrupt."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_DEFAULT_RX_MBOX {
+ display "Default receive message buffer"
+ flavor data
+ calculated 14
+ legal_values 0 to 15
+ description "
+ By default one message buffer will be used for message transmission.
+ This option selects one of the 16 FlexCAN message buffers for
+ transmission."
+ }
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_DEFAULT_TX_MBOX {
+ display "Default transmit message buffer"
+ flavor data
+ calculated 15
+ legal_values 0 to 15
+ description "
+ By default one message buffer will be used for reception of
+ all CAN messages. This option selects one of the 16 message
+ buffers for reception."
+ }
+
+ cdl_component CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_MBOXCFG {
+ display "Message buffer configuration"
+ flavor none
+ active_if CYGINT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]
+ description "
+ The FlexCAN module contains 16 flexible message buffers of 0-8 bytes
+ data length, each configurable as Rx or Tx, all supporting standard and
+ extended messages. At the moment a fixed configuration is used for
+ TX and RX message buffers but in future this may be configurable."
+
+ cdl_component CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_MBOX14_CFG {
+ display "Message buffer 14 configuration"
+ flavor none
+ active_if CYGINT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]
+ description "
+ Configuration of FlexCAN message buffer 14."
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_ISR_PRIORITY_FLEXCAN[set ::flexcan]_MBOX14 {
+ display "Interrupt priority."
+ flavor data
+ default_value is_loaded(CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_MBOX14) ? \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_MBOX14 : \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN
+ legal_values CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN to CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MAX
+ description "
+ Interrupt priority for message buffer 14"
+ }
+
+ cdl_option CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_MBOX14_IS_TX {
+ display "Use for transmit"
+ flavor bool
+ active_if CYGINT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]
+ calculated 0
+ description "
+ This option controls if this message buffer is used for sending
+ or receiving messages. Currently this option is not configurable
+ and message box 14 is used for reception of CAN messages."
+
+ }
+ }
+
+ cdl_component CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_MBOX15_CFG {
+ display "Message buffer 15 configuration"
+ flavor none
+ active_if CYGINT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]
+ description "
+ Configuration of FlexCAN message buffer 15."
+
+ cdl_option CYGNUM_DEVS_CAN_MCF52xx_ISR_PRIORITY_FLEXCAN[set ::flexcan]_MBOX15 {
+ display "Interrupt priority."
+ flavor data
+ default_value is_loaded(CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_MBOX15) ? \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_FLEXCAN[set ::flexcan]_MBOX15 : \
+ CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN
+ legal_values CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN to CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MAX
+ description "
+ Interrupt priority for message buffer 15"
+ }
+
+ cdl_option CYGOPT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]_MBOX15_IS_TX {
+ display "Use for transmit"
+ flavor bool
+ active_if CYGINT_DEVS_CAN_MCF52xx_FLEXCAN[set ::flexcan]
+ calculated 1
+ description "
+ This option controls if this message buffer is used for sending
+ or receiving messages. Currently this option is not configurable
+ and message box 15 is used for transmission of CAN messages."
+
+ }
+ }
+ }
+ }
+ }
+
+
+ cdl_component CYGPKG_IO_CAN_MCF52xx_FLEXCAN_OPTIONS {
+ display "FlexCAN device driver build options"
+ flavor none
+ description "
+ Package specific build options including control over
+ compiler flags used only in building this package,
+ and details of which tests are built."
+
+ cdl_option CYGPKG_IO_CAN_MCF52xx_FLEXCAN_CFLAGS_ADD {
+ display "Additional compiler flags"
+ flavor data
+ no_define
+ default_value { "" }
+ description "
+ This option modifies the set of compiler flags for
+ building these CAN device drivers. These flags are
+ used in addition to the set of global flags."
+ }
+
+ cdl_option CYGPKG_IO_CAN_MCF52xx_FLEXCAN_CFLAGS_REMOVE {
+ display "Suppressed compiler flags"
+ flavor data
+ no_define
+ default_value { "" }
+ description "
+ This option modifies the set of compiler flags for
+ building these CAN device drivers. These flags are
+ removed from the set of global flags if present."
+ }
+ }
+}
diff -urN ecos_web_cvs/ecos/packages/devs/can/m68k/mcf52xx/current/src/can_mcf52xx.c ecos/ecos/packages/devs/can/m68k/mcf52xx/current/src/can_mcf52xx.c
--- ecos_web_cvs/ecos/packages/devs/can/m68k/mcf52xx/current/src/can_mcf52xx.c 1970-01-01 01:00:00.000000000 +0100
+++ ecos/ecos/packages/devs/can/m68k/mcf52xx/current/src/can_mcf52xx.c 2005-05-23 22:51:02.000000000 +0200
@@ -0,0 +1,1398 @@
+//==========================================================================
+//
+// devs/serial/m68k/flexcan/current/src/can_mcf_flexcan.c
+//
+// CAN driver for Motorola coldfire processors
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Uwe Kindler
+// Contributors: Uwe Kindler
+// Date: 2005-05-12
+// Purpose: support coldfire on-chip flexcan moduls
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+
+//==========================================================================
+// INCLUDES
+//==========================================================================
+#include <pkgconf/system.h>
+#include <pkgconf/io_can.h>
+#include <pkgconf/devs_can_mcf52xx_flexcan.h>
+
+#include <cyg/infra/diag.h>
+
+#include <cyg/io/io.h>
+#include <cyg/io/devtab.h>
+#include <cyg/io/can.h>
+
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_io.h>
+
+
+//===========================================================================
+// DEFINES
+//===========================================================================
+
+//
+// we define our own ste of register bits in order to be independent from
+// platform specific names
+//
+
+//---------------------------------------------------------------------------
+// MCR regsiter bits
+//
+#define FLEXCAN_MCR_STOP (0x01 << 15)
+#define FLEXCAN_MCR_FRZ (0x01 << 14)
+#define FLEXCAN_MCR_HALT (0x01 << 12)
+#define FLEXCAN_MCR_NOTRDY (0x01 << 11)
+#define FLEXCAN_MCR_WAKEMSK (0x01 << 10)
+#define FLEXCAN_MCR_SOFTRST (0x01 << 9)
+#define FLEXCAN_MCR_FRZACK (0x01 << 8)
+#define FLEXCAN_MCR_SUPV (0x01 << 7)
+#define FLEXCAN_MCR_SELFWAKE (0x01 << 6)
+#define FLEXCAN_MCR_APS (0x01 << 5)
+#define FLEXCAN_MCR_STOPACK (0x01 << 4)
+
+
+//---------------------------------------------------------------------------
+// CTRL0 register bits
+//
+#define FLEXCAN_CTRL0_BOFFMSK (0x01 << 7)
+#define FLEXCAN_CTRL0_ERRMASK (0x01 << 6)
+#define FLEXCAN_CTRL0_RXMODE (0x01 << 2)
+#define FLEXCAN_CTRL0_RXMODE_0_DOMINANT (0x00 << 2)
+#define FLEXCAN_CTRL0_RXMODE_1_DOMINANT (0x01 << 2)
+#define FLEXCAN_CTRL0_TXMODE_MASK (0x03 << 0)
+#define FLEXCAN_CTRL0_TXMODE_SHIFT 0
+#define FLEXCAN_CTRL0_TXMODE_FULL_0_DOMINANT (0x00 << 0)
+#define FLEXCAN_CTRL0_TXMODE_FULL_1_DOMINANT (0x01 << 0)
+#define FLEXCAN_CTRL0_TXMODE_OPEN_0_DOMINANT (0x02 << 0)
+
+
+//---------------------------------------------------------------------------
+// CTRL1 register bits
+//
+#define FLEXCAN_CTRL1_SAMP (0x01 << 7)
+#define FLEXCAN_CTRL1_TSYNC (0x01 << 5)
+#define FLEXCAN_CTRL1_LBUF (0x01 << 4)
+#define FLEXCAN_CTRL1_LOM (0x01 << 3)
+#define FLEXCAN_CTRL1_PROPSEG_MASK (0x07 << 0)
+#define FLEXCAN_CTRL1_PROPSEG_SHIFT 0
+
+
+//---------------------------------------------------------------------------
+// CTRL2 register bits
+//
+#define FLEXCAN_CTRL2_RJW_MASK (0x03 << 6)
+#define FLEXCAN_CTRL2_RJW_SHIFT 6
+#define FLEXCAN_CTRL2_PSEG1_MASK (0x07 << 3)
+#define FLEXCAN_CTRL2_PSEG1_SHIFT 3
+#define FLEXCAN_CTRL2_PSEG2_MASK (0x07 << 0)
+#define FLEXCAN_CTRL2_PSEG2_SHIFT 0
+
+//---------------------------------------------------------------------------
+// ESTAT register bits
+//
+#define FLEXCAN_ESTAT_BITERR_MASK (0x03 << 14)
+#define FLEXCAN_ESTAT_BITERR_SHIFT 14
+#define FLEXCAN_ESTAT_BITERR_NONE (0x00 << 14)
+#define FLEXCAN_ESTAT_BITERR_DOMINANT_RECESSIVE (0x01 << 14)
+#define FLEXCAN_ESTAT_BITERR_RECESSIVE_DOMINANT (0x02 << 14)
+#define FLEXCAN_ESTAT_ACKERR (0x01 << 13)
+#define FLEXCAN_ESTAT_CRCERR (0x01 << 12)
+#define FLEXCAN_ESTAT_FORMERR (0x01 << 11)
+#define FLEXCAN_ESTAT_STUFFERR (0x01 << 10)
+#define FLEXCAN_ESTAT_TXWARN (0x01 << 9)
+#define FLEXCAN_ESTAT_RXWARN (0x01 << 8)
+#define FLEXCAN_ESTAT_IDLE (0x01 << 7)
+#define FLEXCAN_ESTAT_TX_RX (0x01 << 6)
+#define FLEXCAN_ESTAT_FCS_MASK (0x03 << 4)
+#define FLEXCAN_ESTAT_FCS_SHIFT 4
+#define FLEXCAN_ESTAT_FCS_ERROR_ACTIVE (0x00 << 4)
+#define FLEXCAN_ESTAT_FCS_ERROR_PASSIVE (0x01 << 4)
+#define FLEXCAN_ESTAT_BOFFINT (0x01 << 2)
+#define FLEXCAN_ESTAT_ERRINT (0x01 << 1)
+#define FLEXCAN_ESTAT_WAKEINT (0x01 << 0)
+
+//
+// For receive event calls we use these two identifiers for
+// err and bus off events - message boxes use 0 - 15
+//
+#define FLEXCAN_ERR_EVENT 16
+#define FLEXCAN_BUSOFF_EVENT 17
+
+
+//---------------------------------------------------------------------------
+// message buffer cfg bits
+//
+#define MBOX_RXCODE_NOT_ACTIVE 0x00
+#define MBOX_RXCODE_BUSY 0x10
+#define MBOX_RXCODE_EMPTY 0x40
+#define MBOX_RXCODE_FULL 0x20
+#define MBOX_RXCODE_OVERRUN 0x60
+
+#define MBOX_TXCODE_NOT_READY 0x80
+#define MBOX_TXCODE_TRANSMIT 0xC0
+#define MBOX_TXCODE_RESPONSE 0xA0
+
+#define MBOX_DATA_FRAME 0x00 // data frame
+#define MBOX_REMOTE_FRAME 0x01 // remote frame
+#define MBOX_STD_ID 0x00 // standard identifier
+#define MBOX_EXT_ID 0x01 // remote identifier
+#define MBOX_TX 0x08 // tx message box
+#define MBOX_RX 0x00 // rx messge box
+
+#define MBOX_CFG_IDE 0x08
+#define MBOX_CFG_RTR_EXT 0x01
+#define MBOX_CFG_RTR_STD 0x10
+#define MBOX_CFG_SSR 0x10
+#define MBOX_CFG_DLC_MASK 0x0F
+#define MBOX_CFG_STAT_MASK 0xF0
+
+
+//===========================================================================
+// DATA TYPES
+//===========================================================================
+//
+// configuration info for flexcan message buffer
+//
+typedef struct flexcan_mbox_info_st
+{
+ cyg_vector_t isr_vec;
+ int isr_priority;
+ cyg_interrupt interrupt;
+ cyg_handle_t interrupt_handle;
+ cyg_uint8 num;
+} flexcan_mbox_info;
+
+//
+// flexcan interrupt (busoff, err, wake) data
+//
+typedef struct flexcan_int_st
+{
+ cyg_vector_t isr_vec;
+ int isr_priority;
+ cyg_interrupt interrupt;
+ cyg_handle_t interrupt_handle;
+} flexcan_int;
+
+//
+// flexcan message box initialisation
+//
+#define FLEXCAN_MBOX_INIT(_mbox0_vec, _prio, _mbox_no) { \
+ isr_vec : (_mbox0_vec) + (_mbox_no), \
+ isr_priority : (_prio), \
+ num : (_mbox_no) \
+}
+
+//
+// Interrupt initialisation
+//
+#define FLEXCAN_INT_INIT(_vec, _prio) \
+{ \
+ isr_vec : (_vec), \
+ isr_priority : (_prio) \
+}
+
+//
+// flexcan configuration
+//
+typedef struct flexcan_info
+{
+ cyg_uint8 *base; // base address of flexcan modul
+ cyg_vector_t isr_vec_mbox0; // vector number of ISR vector of first message box
+ flexcan_mbox_info rx_mbox; // rx message box interrupt
+ flexcan_mbox_info tx_mbox; // tx message box interrupt
+ cyg_uint32 last_tx_id; // last transmitted message
+ bool tx_busy; // indicates if transmit process ic currently running
+
+ cyg_uint32 rxgmask; // acceptance filter for message box 0 - 13
+ cyg_uint32 rx14mask; // acceptance filter for message box 14
+ cyg_uint32 rx15mask; // acceptance filter for message box 15
+
+ flexcan_int boff_int; // bus off interrupt data
+ flexcan_int err_int; // error interrupt data
+
+ cyg_uint32 timeout_rd;
+ cyg_uint32 timeout_wr;
+#ifdef FLEXCAN_CAN_STATS
+ cyg_uint32 isr_count;
+ cyg_uint32 dsr_count;
+ cyg_uint32 rx_bytes;
+ cyg_uint32 tx_bytes;
+ cyg_uint32 rx_errors;
+#endif
+} flexcan_info;
+
+
+//
+// flexcan info initialisation
+//
+#define FLEXCAN_INFO(_l, \
+ _baseaddr, \
+ _isr_vec_mbox0, \
+ _rx_mbox_no, _rx_isr_prio, \
+ _tx_mbox_no, _tx_isr_prio, \
+ _boff_isr_vec, _boff_isr_prio, \
+ _err_isr_vec, _err_isr_prio) \
+flexcan_info _l = { \
+ (void *)( _baseaddr), \
+ (_isr_vec_mbox0), \
+ FLEXCAN_MBOX_INIT((_isr_vec_mbox0), (_rx_isr_prio), (_rx_mbox_no)), \
+ FLEXCAN_MBOX_INIT((_isr_vec_mbox0), (_tx_isr_prio), (_tx_mbox_no)), \
+ 0xFFFFFFFF, \
+ false, \
+ rxgmask : CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_RXMASK_GLOBAL, \
+ rx14mask : CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_RXMASK_14, \
+ rx15mask : CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_RXMASK_15, \
+ boff_int : FLEXCAN_INT_INIT(_boff_isr_vec, _boff_isr_prio), \
+ err_int : FLEXCAN_INT_INIT(_err_isr_vec, _err_isr_prio) \
+};
+
+
+//===========================================================================
+// GLOBAL DATA
+//===========================================================================
+//
+// Note: two levels of macro are required to get proper expansion.
+//
+#define _FLEXCAN_MBOX_INTPRIO(n) CYGNUM_DEVS_CAN_MCF52xx_ISR_PRIORITY_FLEXCAN0_MBOX##n
+#define FLEXCAN_MBOX_INTPRIO(n) _FLEXCAN_MBOX_INTPRIO(n)
+
+//
+// FlexCAN channel initialisation
+//
+FLEXCAN_INFO(flexcan_can0_info,
+ HAL_MCF52xx_MBAR + HAL_MCF52xx_FLEXCAN0_BASE,
+ HAL_MCF52xx_FLEXCAN0_MBOX0_ISRVEC,
+ CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_DEFAULT_RX_MBOX,
+ FLEXCAN_MBOX_INTPRIO(CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_DEFAULT_RX_MBOX),
+ CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_DEFAULT_TX_MBOX,
+ FLEXCAN_MBOX_INTPRIO(CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_DEFAULT_TX_MBOX),
+ HAL_MCF52xx_FLEXCAN0_BOFF_ISRVEC,
+ CYGNUM_DEVS_CAN_MCF52xx_ISR_PRIORITY_FLEXCAN0_BOFFINT,
+ HAL_MCF52xx_FLEXCAN0_ERR_ISRVEC,
+ CYGNUM_DEVS_CAN_MCF52xx_ISR_PRIORITY_FLEXCAN0_ERRINT);
+
+//
+// message box structure
+//
+typedef struct flexcan_mbox
+{
+ cyg_uint8 timestamp;
+ cyg_uint8 ctrlstat;
+ cyg_uint16 id_hi;
+ cyg_uint16 id_lo;
+ cyg_uint8 data[8];
+ cyg_uint16 reserved;
+} flexcan_mbox;
+
+//
+// flexcan register layout
+//
+typedef struct flexcan_regs
+{
+ cyg_uint16 CANMCR; // 0x00
+ cyg_uint16 reserved0[2]; // 0x02
+ cyg_uint8 CANCTRL0; // 0x06
+ cyg_uint8 CANCTRL1; // 0x07
+ cyg_uint8 PRESDIV; // 0x08
+ cyg_uint8 CANCTRL2; // 0x09
+ cyg_uint16 TIMER; // 0x0A
+ cyg_uint16 reserved1[2]; // 0x0C
+ cyg_uint16 RXGMASK_HI; // 0x10
+ cyg_uint16 RXGMASK_LO; // 0x12
+ cyg_uint16 RX14MASK_HI; // 0x14
+ cyg_uint16 RX14MASK_LO; // 0x16
+ cyg_uint16 RX15MASK_HI; // 0x18
+ cyg_uint16 RX15MASK_LO; // 0x1A
+ cyg_uint16 reserved2[2]; // 0x1C
+ cyg_uint16 ESTAT; // 0x20
+ cyg_uint16 IMASK; // 0x22
+ cyg_uint16 IFLAG; // 0x24
+ cyg_uint8 RXERRCNT; // 0x26
+ cyg_uint8 TXERRCNT; // 0x27
+ cyg_uint16 reserved3[44];// 0x28
+ flexcan_mbox mbox[16]; // 0x80
+} flexcan_regs;
+
+
+//===========================================================================
+// LOCAL DATA
+//===========================================================================
+static cyg_uint16 flexcan_baud_rates[] = {
+ 0, // Unused
+ 10, // 10 kbit/s
+ 20, // 20
+ 50, // 50
+ 100, // 100
+ 125, // 125
+ 250, // 250
+ 500, // 500
+ 800, // 800
+ 1000, // 1000 kbit/s
+};
+
+
+//===========================================================================
+// PROTOTYPES
+//===========================================================================
+static bool flexcan_init(struct cyg_devtab_entry* devtab_entry);
+static Cyg_ErrNo flexcan_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name);
+static Cyg_ErrNo flexcan_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len);
+static bool flexcan_putmsg(can_channel *priv, cyg_can_message *pmsg, void *pdata);
+static bool flexcan_getevent(can_channel *priv, cyg_can_event *pevent, void *pdata);
+static void flexcan_start_xmit(can_channel* chan);
+static void flexcan_stop_xmit(can_channel* chan);
+
+//
+// TX and RX ISRs and DSRs
+//
+static cyg_uint32 flexcan_mbox_rx_isr(cyg_vector_t, cyg_addrword_t);
+static void flexcan_mbox_rx_dsr(cyg_vector_t, cyg_ucount32, cyg_addrword_t);
+static cyg_uint32 flexcan_mbox_tx_isr(cyg_vector_t, cyg_addrword_t);
+static void flexcan_mbox_tx_dsr(cyg_vector_t, cyg_ucount32, cyg_addrword_t);
+
+//
+// All other flexcan interrupt handlers
+//
+static cyg_uint32 flexcan_err_isr(cyg_vector_t, cyg_addrword_t);
+static void flexcan_err_dsr(cyg_vector_t, cyg_ucount32, cyg_addrword_t);
+static cyg_uint32 flexcan_busoff_isr(cyg_vector_t, cyg_addrword_t);
+static void flexcan_busoff_dsr(cyg_vector_t, cyg_ucount32, cyg_addrword_t);
+
+
+static bool flexcan_cfg_mbox_tx(flexcan_mbox *pmbox, cyg_can_message *pmsg);
+static void flexcan_cfg_mbox_rx(flexcan_mbox *pmbox, cyg_uint32 canid, cyg_uint8 ext);
+static void flexcan_read_from_mbox(can_channel *chan, cyg_uint8 mbox, cyg_can_event *pevent, cyg_uint8 *ctrlstat);
+static void flexcan_set_acceptance_mask(cyg_uint16 *rxmask_reg, cyg_uint32 mask, cyg_uint8 ext);
+static void flexcan_start_chip(can_channel *chan);
+static bool flexcan_set_baud(can_channel *chan, cyg_uint16 baudrate);
+static bool flexcan_config(can_channel* chan, cyg_can_info_t* config, cyg_bool init);
+
+
+CAN_LOWLEVEL_FUNS(flexcan_lowlevel_funs,
+ flexcan_putmsg,
+ flexcan_getevent,
+ flexcan_set_config,
+ flexcan_start_xmit,
+ flexcan_stop_xmit
+ );
+
+
+cyg_can_event flexcan_can0_rxbuf[CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_RX]; // buffer for 32 rx can events
+cyg_can_message flexcan_can0_txbuf[CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_TX]; // buffer for 32 tx can messageds
+
+
+CAN_CHANNEL_USING_INTERRUPTS(flexcan_can0_chan,
+ flexcan_lowlevel_funs,
+ flexcan_can0_info,
+ CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_KBAUD),
+ flexcan_can0_txbuf, CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_TX,
+ flexcan_can0_rxbuf, CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_RX
+ );
+
+
+DEVTAB_ENTRY(flexcan_devtab,
+ CYGDAT_DEVS_CAN_MCF52xx_FLEXCAN0_NAME,
+ 0, // Does not depend on a lower level interface
+ &cyg_io_can_devio,
+ flexcan_init,
+ flexcan_lookup, // CAN driver may need initializing
+ &flexcan_can0_chan
+ );
+
+
+//===========================================================================
+// Lookup the device and return its handle
+//===========================================================================
+static Cyg_ErrNo
+flexcan_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name)
+{
+ can_channel* chan = (can_channel*) (*tab)->priv;
+ (chan->callbacks->can_init)(chan);
+
+ return ENOERR;
+}
+
+
+//===========================================================================
+// Set device configuration
+//===========================================================================
+static Cyg_ErrNo
+flexcan_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
+{
+ Cyg_ErrNo res = ENOERR;
+
+ switch(key)
+ {
+ case CYG_IO_SET_CONFIG_CAN_INFO:
+ {
+ cyg_can_info_t* config = (cyg_can_info_t*) buf;
+ if (*len < sizeof(cyg_can_info_t))
+ {
+ return -EINVAL;
+ }
+ *len = sizeof(cyg_can_info_t);
+ if (!flexcan_config(chan, config, false))
+ {
+ return -EINVAL;
+ }
+ }
+ break;
+ } // switch (key)
+
+ return res;
+}
+
+
+//===========================================================================
+// Read one event from can hardware
+//===========================================================================
+static bool flexcan_getevent(can_channel *chan, cyg_can_event *pevent, void *pdata)
+{
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint8 mbox_ctrlstat;
+ bool res = true;
+ cyg_uint8 event_id = *((cyg_uint8 *)pdata);
+ cyg_uint16 estat;
+
+ //
+ // if event_id is 0 - 15 the we have a message box event - if is
+ //
+ if (event_id < FLEXCAN_ERR_EVENT)
+ {
+ //
+ // read data from message box - during processing of this function
+ // the message box is locked and cannot receive further messages
+ //
+ flexcan_read_from_mbox(chan, event_id, pevent, &mbox_ctrlstat);
+
+#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT
+ if (pevent->msg.id == info->last_tx_id)
+ {
+ pevent->type = CYGNUM_CAN_EVENT_TX;
+ }
+ else
+ {
+ pevent->type = CYGNUM_CAN_EVENT_RX;
+ }
+#else // !CYGOPT_IO_CAN_TX_EVENT_SUPPORT
+ //
+ // If tx events are not supported and we received a self transmitted frame
+ // then this is not really an rx event and we return false. We rely on the
+ // fact here that two devices in network do not send the same identifier
+ //
+ if (pevent->msg.id == info->last_tx_id) {
+ info->last_tx_id = 0xFFFFFFFF; // set last received ID to an invalid value
+ res = false;
+ }
+
+ pevent->type = CYGNUM_CAN_EVENT_RX;
+#endif
+
+ //
+ // check if an overun occured in this message box
+ //
+ if ((mbox_ctrlstat & MBOX_RXCODE_OVERRUN) == MBOX_RXCODE_OVERRUN)
+ {
+ pevent->type |= CYGNUM_CAN_EVENT_OVERRUN_RX;
+ }
+ }
+ else // (event_id >= FLEXCAN_ERR_EVENT)
+ {
+ //
+ // We have an status event - check if it is an bus off interrupt or an
+ // error interrupt and provide error information to upper layer
+ //
+ HAL_READ_UINT16(&flexcan->ESTAT, estat);
+ pevent->msg.data[0] = estat & 0xFF;
+ pevent->msg.data[1] = (estat >> 8) & 0xFF;
+ HAL_READ_UINT8(&flexcan->RXERRCNT, pevent->msg.data[2]);
+ HAL_READ_UINT8(&flexcan->TXERRCNT, pevent->msg.data[3]);
+ switch (event_id)
+ {
+ case FLEXCAN_ERR_EVENT :
+ //
+ // indicate error passive event and provide content of estat register
+ // for a more precise error information
+ //
+ if (estat & FLEXCAN_ESTAT_FCS_ERROR_PASSIVE)
+ {
+ pevent->type = CYGNUM_CAN_EVENT_ERR_PASSIVE;
+ }
+ //
+ // If we are not in error passive state then we check if the
+ // error counters reached the warning level
+ //
+ else
+ {
+ //
+ // indicate tx error counter warning level reached
+ //
+ if (estat & FLEXCAN_ESTAT_TXWARN)
+ {
+ pevent->type |= CYGNUM_CAN_EVENT_WARNING_TX;
+ }
+
+ //
+ // indicate rx error counter warning level reached
+ //
+ if (estat & FLEXCAN_ESTAT_RXWARN)
+ {
+ pevent->type |= CYGNUM_CAN_EVENT_WARNING_RX;
+ }
+ }
+ break;
+
+ case FLEXCAN_BUSOFF_EVENT:
+ pevent->type = CYGNUM_CAN_EVENT_BUS_OFF;
+ break;
+ } // switch (event_id)
+ }
+
+ return res;
+}
+
+
+//===========================================================================
+// Send one CAN message to CAN hardware
+//===========================================================================
+static bool flexcan_putmsg(can_channel *chan, cyg_can_message *pmsg, void *pdata)
+{
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint8 mbox = *((cyg_uint8 *)pdata);
+ cyg_uint16 iflag;
+
+ HAL_READ_UINT16(&flexcan->IFLAG, iflag);
+
+ //
+ // check if device is busy sending a message
+ //
+ if (info->tx_busy)
+ {
+ //
+ // if devise is busy and the interrupt flag is set, then we know
+ // that device is not busy any longer - if more message boxes are
+ // used for transmitting then tx_busy should be part of a message box
+ // structure to keep track of the state of different message boxes
+ //
+ if (iflag & (0x0001 << mbox))
+ {
+ HAL_WRITE_UINT16(&flexcan->IFLAG, (0x0001 << mbox));
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ info->tx_busy = true; // mark transmitter as busy
+ info->last_tx_id = pmsg->id; // store message in order to identify self recieved frames
+ flexcan_cfg_mbox_tx(&flexcan->mbox[mbox], pmsg);
+
+ return true;
+}
+
+
+//===========================================================================
+// Flexcan start xmit
+//===========================================================================
+static void flexcan_start_xmit(can_channel* chan)
+{
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint16 imask;
+ CYG_INTERRUPT_STATE saved_state;
+
+ HAL_DISABLE_INTERRUPTS(saved_state);
+
+ //
+ // Now enable message box 15 interrupts
+ //
+ HAL_READ_UINT16(&flexcan->IMASK, imask);
+ HAL_WRITE_UINT16(&flexcan->IMASK, imask | (0x0001 << info->tx_mbox.num));
+
+ //
+ // kick transmitter
+ //
+ chan->callbacks->xmt_msg(chan, &info->tx_mbox.num); // Kick transmitter (if necessary)
+
+ HAL_RESTORE_INTERRUPTS(saved_state);
+}
+
+
+//===========================================================================
+// Flexcan start xmit
+//===========================================================================
+static void flexcan_stop_xmit(can_channel* chan)
+{
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint16 imask;
+ CYG_INTERRUPT_STATE saved_state;
+
+ HAL_DISABLE_INTERRUPTS(saved_state);
+
+ //
+ // Now disable message box 15 interrupts
+ //
+ HAL_READ_UINT16(&flexcan->IMASK, imask);
+ HAL_WRITE_UINT16(&flexcan->IMASK, imask & ~(0x0001 << info->tx_mbox.num));
+
+ HAL_RESTORE_INTERRUPTS(saved_state);
+}
+
+
+//===========================================================================
+// Configure flexcan channel
+//===========================================================================
+static bool flexcan_config(can_channel* chan, cyg_can_info_t* config, cyg_bool init)
+{
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint16 tmp16;
+ cyg_uint8 tmp8;
+ cyg_uint8 i;
+
+ if (init)
+ {
+#if defined(CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN0) && defined(HAL_MCF52xx_FLEXCAN0_PROC_INIT)
+ if (info == &flexcan_can0_info) {
+ HAL_MCF52xx_FLEXCAN0_PROC_INIT();
+ }
+#endif
+
+ //
+ // Issue a reset in order to go into halt mode. The reset will set the
+ // the halt bit in mcr
+ //
+ HAL_READ_UINT16(&flexcan->CANMCR, tmp16);
+ tmp16 &= ~FLEXCAN_MCR_FRZ;
+ HAL_WRITE_UINT16(&flexcan->CANMCR, tmp16);
+ tmp16 |= FLEXCAN_MCR_SOFTRST;
+ HAL_WRITE_UINT16(&flexcan->CANMCR, tmp16);
+ HAL_DELAY_US(10);
+
+ //
+ // Check reset status
+ //
+ HAL_READ_UINT16(&flexcan->CANMCR, tmp16);
+ if (tmp16 & FLEXCAN_MCR_SOFTRST)
+ {
+ return false;
+ }
+
+ //
+ // Initialize the transmit and receive pin modes
+ //
+ HAL_WRITE_UINT8(&flexcan->CANCTRL0 , (FLEXCAN_CTRL0_TXMODE_FULL_0_DOMINANT
+ | FLEXCAN_CTRL0_RXMODE_0_DOMINANT)
+ & ~FLEXCAN_CTRL0_BOFFMSK
+ & ~FLEXCAN_CTRL0_ERRMASK);
+
+ //
+ // setup message box acceptance filter
+ //
+ flexcan_set_acceptance_mask(&flexcan->RXGMASK_HI, info->rxgmask, 0);
+ flexcan_set_acceptance_mask(&flexcan->RX14MASK_HI, info->rx14mask, 0);
+ flexcan_set_acceptance_mask(&flexcan->RX15MASK_HI, info->rx15mask, 0);
+ } // if (init)
+
+ //
+ // stop chip
+ //
+ HAL_READ_UINT16(&flexcan->CANMCR, tmp16);
+ HAL_WRITE_UINT16(&flexcan->CANMCR, tmp16 | FLEXCAN_MCR_HALT);
+
+ //
+ // deactivate all message buffers - this is mandatory for configuration
+ // of message buffers
+ //
+ for (i = 0; i < 16; ++i)
+ {
+ HAL_WRITE_UINT16(&flexcan->mbox[i], MBOX_RXCODE_NOT_ACTIVE);
+ }
+ //
+ // mask all interrupts
+ //
+ HAL_WRITE_UINT16(&flexcan->IMASK, 0x0000);
+ HAL_READ_UINT8(&flexcan->CANCTRL0, tmp8);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL0, tmp8 & ~(FLEXCAN_CTRL0_BOFFMSK | FLEXCAN_CTRL0_ERRMASK));
+
+ flexcan_set_baud(chan, config->baud);
+
+ //
+ // setup bus arbitration mode - the LBUF bit defines the
+ // transmit-first scheme 0 = message buffer with lowest ID
+ // 1 = message buffer with lowest number. We use lowest ID here
+ //
+ HAL_READ_UINT8(&flexcan->CANCTRL1, tmp8);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL1, (tmp8 & ~FLEXCAN_CTRL1_LBUF));
+
+ //
+ // Message box 14 is our receiv message box. We configure it for
+ // reception of any message
+ //
+ flexcan_cfg_mbox_rx(&flexcan->mbox[info->rx_mbox.num], 0x100, 0);
+ flexcan_set_acceptance_mask(&flexcan->RX14MASK_HI, 0, 0);
+
+ //
+ // enable the rx interrupt for mbox 0 (tx interrupt are enabled in start xmit)
+ // bus off interrupt and error interrupt
+ //
+ HAL_WRITE_UINT16(&flexcan->IMASK, (0x0001 << info->rx_mbox.num));
+ HAL_READ_UINT8(&flexcan->CANCTRL0, tmp8);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL0, tmp8 | (FLEXCAN_CTRL0_BOFFMSK | FLEXCAN_CTRL0_ERRMASK));
+
+ //
+ // now we can start the chip
+ //
+ flexcan_start_chip(chan);
+
+ //
+ // store new config values
+ //
+ if (config != &chan->config)
+ {
+ chan->config = *config;
+ }
+
+ return true;
+}
+
+//===========================================================================
+// CAN INIT
+//
+/// First initialisation and reset of CAN modul.
+//===========================================================================
+static bool flexcan_init(struct cyg_devtab_entry* devtab_entry)
+{
+ can_channel *chan = (can_channel*)devtab_entry->priv;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+
+ if (!flexcan_config(chan, &chan->config, true))
+ {
+ return false;
+ }
+
+ //
+ // prepare message box interrupt for message box 0 - the rx message box
+ //
+ cyg_drv_interrupt_create(info->rx_mbox.isr_vec,
+ info->rx_mbox.isr_priority,
+ (cyg_addrword_t) chan,
+ &flexcan_mbox_rx_isr,
+ &flexcan_mbox_rx_dsr,
+ &(info->rx_mbox.interrupt_handle),
+ &(info->rx_mbox.interrupt));
+ cyg_drv_interrupt_attach(info->rx_mbox.interrupt_handle);
+ cyg_drv_interrupt_unmask(info->rx_mbox.isr_vec);
+
+ //
+ // prepare message box interrupt for message box 15 - the tx message box
+ //
+ cyg_drv_interrupt_create(info->tx_mbox.isr_vec,
+ info->tx_mbox.isr_priority,
+ (cyg_addrword_t) chan,
+ &flexcan_mbox_tx_isr,
+ &flexcan_mbox_tx_dsr,
+ &(info->tx_mbox.interrupt_handle),
+ &(info->tx_mbox.interrupt));
+ cyg_drv_interrupt_attach(info->tx_mbox.interrupt_handle);
+ cyg_drv_interrupt_unmask(info->tx_mbox.isr_vec);
+
+ //
+ // prepare error interrupt
+ //
+ cyg_drv_interrupt_create(info->err_int.isr_vec,
+ info->err_int.isr_priority,
+ (cyg_addrword_t) chan,
+ &flexcan_err_isr,
+ &flexcan_err_dsr,
+ &(info->err_int.interrupt_handle),
+ &(info->err_int.interrupt));
+ cyg_drv_interrupt_attach(info->err_int.interrupt_handle);
+ cyg_drv_interrupt_unmask(info->err_int.isr_vec);
+
+ //
+ // prepare busoff interrupt
+ //
+ cyg_drv_interrupt_create(info->boff_int.isr_vec,
+ info->boff_int.isr_priority,
+ (cyg_addrword_t) chan,
+ &flexcan_busoff_isr,
+ &flexcan_busoff_dsr,
+ &(info->boff_int.interrupt_handle),
+ &(info->boff_int.interrupt));
+ cyg_drv_interrupt_attach(info->boff_int.interrupt_handle);
+ cyg_drv_interrupt_unmask(info->boff_int.isr_vec);
+
+ return true;
+}
+
+
+//===========================================================================
+// Flexcan error interrupt handler
+//===========================================================================
+static cyg_uint32 flexcan_err_isr(cyg_vector_t vec, cyg_addrword_t data)
+{
+ can_channel *chan = (can_channel *)data;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint8 ctrl0;
+ cyg_uint16 estat;
+
+ //
+ // first we disable error interrupts - DSR will reenable it later
+ //
+ HAL_READ_UINT8(&flexcan->CANCTRL0, ctrl0);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL0, ctrl0 & ~FLEXCAN_CTRL0_ERRMASK);
+
+ //
+ // for clearing the interrupt we first read the flag register as 1
+ // and then write it as 1 (and not as zero like the manual stated)
+ // we clear only the flag of this interrupt and leave all other
+ // message box interrupts untouched
+ //
+ HAL_READ_UINT16(&flexcan->ESTAT, estat);
+ HAL_WRITE_UINT16(&flexcan->ESTAT, FLEXCAN_ESTAT_ERRINT);
+
+ //
+ // On the mcf5272 there is no need to acknowledge internal
+ // interrupts, only external ones.
+ // cyg_drv_interrupt_acknowledge(vec);
+ //
+ return CYG_ISR_CALL_DSR;
+}
+
+
+//===========================================================================
+// DSR for all interrupts that are no message box interrupts
+//===========================================================================
+static void flexcan_err_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
+{
+ can_channel *chan = (can_channel *)data;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint8 ctrl0;
+ cyg_uint8 event_id = FLEXCAN_ERR_EVENT;
+
+ //
+ // signal CAN event to generic IO CAN driver - it will do any further
+ // processing
+ //
+ chan->callbacks->rcv_event(chan, &event_id);
+
+ //
+ // reenable bus off interrupts
+ //
+ HAL_READ_UINT8(&flexcan->CANCTRL0, ctrl0);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL0, ctrl0 | FLEXCAN_CTRL0_ERRMASK);
+}
+
+
+//===========================================================================
+// Bus off interrupt handler
+//===========================================================================
+static cyg_uint32 flexcan_busoff_isr(cyg_vector_t vec, cyg_addrword_t data)
+{
+ can_channel *chan = (can_channel *)data;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint8 ctrl0;
+ cyg_uint16 estat;
+
+ //
+ // first we disable bus off interrupts - DSR will reenable it later
+ //
+ HAL_READ_UINT8(&flexcan->CANCTRL0, ctrl0);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL0, ctrl0 & ~FLEXCAN_CTRL0_BOFFMSK);
+
+ //
+ // for clearing the interrupt we first read the flag register as 1
+ // and then write it as 1 (and not as zero like the manual stated)
+ // we clear only the flag of this interrupt and leave all other
+ // message box interrupts untouched
+ //
+ HAL_READ_UINT16(&flexcan->ESTAT, estat);
+ HAL_WRITE_UINT16(&flexcan->ESTAT, FLEXCAN_ESTAT_BOFFINT);
+
+ //
+ // On the mcf5272 there is no need to acknowledge internal
+ // interrupts, only external ones.
+ // cyg_drv_interrupt_acknowledge(vec);
+ //
+ return CYG_ISR_CALL_DSR;
+}
+
+
+//===========================================================================
+// DSR for all interrupts that are no message box interrupts
+//===========================================================================
+static void flexcan_busoff_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
+{
+ can_channel *chan = (can_channel *)data;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint8 ctrl0;
+ cyg_uint8 event_id = FLEXCAN_BUSOFF_EVENT;
+
+ //
+ // signal CAN event to generic IO CAN driver - it will do any further
+ // processing
+ //
+ chan->callbacks->rcv_event(chan, &event_id);
+
+ //
+ // reenable bus off interrupts
+ //
+ HAL_READ_UINT8(&flexcan->CANCTRL0, ctrl0);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL0, ctrl0 | FLEXCAN_CTRL0_BOFFMSK);
+}
+
+
+//===========================================================================
+// Flexcan message box isr
+//===========================================================================
+static cyg_uint32 flexcan_mbox_rx_isr(cyg_vector_t vec, cyg_addrword_t data)
+{
+ can_channel *chan = (can_channel *)data;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint16 iflag;
+ cyg_uint16 imask;
+
+ //
+ // number of message box can be calculated from vector that cause
+ // interrupt - we pass this message box number as additional data to the
+ // callback because it is required in the receive event function later
+ //
+ cyg_uint8 mbox = vec - info->isr_vec_mbox0;
+
+ //
+ // first we disable interrupts of this message box - the DSR will
+ // reenable it later
+ //
+ HAL_READ_UINT16(&flexcan->IMASK, imask);
+ HAL_WRITE_UINT16(&flexcan->IMASK, imask & ~(0x0001 << mbox));
+
+ //
+ // for clearing the interrupt we first read the flag register as 1
+ // and then write it as 1 (and not as zero like the manual stated)
+ // we clear only the flag of this interrupt and leave all other
+ // message box interrupts untouched
+ //
+ HAL_READ_UINT16(&flexcan->IFLAG, iflag);
+ HAL_WRITE_UINT16(&flexcan->IFLAG, (0x0001 << mbox));
+
+ //
+ // On the mcf5272 there is no need to acknowledge internal
+ // interrupts, only external ones.
+ // cyg_drv_interrupt_acknowledge(vec);
+ //
+ return CYG_ISR_CALL_DSR;
+}
+
+
+//===========================================================================
+// Flexcan message box dsr
+//===========================================================================
+static void flexcan_mbox_rx_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
+{
+ can_channel *chan = (can_channel *)data;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint16 imask;
+
+ //
+ // number of message box can be calculated from vector that caused
+ // interrupt - we pass this message box number as additional data to the
+ // callback
+ //
+ cyg_uint8 mbox = vec - info->isr_vec_mbox0;
+
+ //
+ // signal CAN event to generic IO CAN driver - it will do any further
+ // processing
+ //
+ chan->callbacks->rcv_event(chan, &mbox);
+
+ //
+ // reenable interrupts for the message box that caused the DSR to run
+ //
+ HAL_READ_UINT16(&flexcan->IMASK, imask);
+ HAL_WRITE_UINT16(&flexcan->IMASK, imask | (0x0001 << mbox));
+}
+
+//===========================================================================
+// Flexcan message box isr
+//===========================================================================
+static cyg_uint32 flexcan_mbox_tx_isr(cyg_vector_t vec, cyg_addrword_t data)
+{
+ can_channel *chan = (can_channel *)data;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint16 iflag;
+ cyg_uint16 imask;
+
+ // number of message box can be calculated from vector that cause
+ // interrupt - we pass this message box number as additional data to the
+ // callback
+ //
+ cyg_uint8 mbox = vec - info->isr_vec_mbox0;
+
+ //
+ // first we disable interrupts of this message box - the DSR will
+ // reenable it later
+ //
+ HAL_READ_UINT16(&flexcan->IMASK, imask);
+ HAL_WRITE_UINT16(&flexcan->IMASK, imask & ~(0x0001 << mbox));
+
+ //
+ // for clearing the interrupt we first read the flag register as 1
+ // and then write it as 1 (and not as zero like the manual stated)
+ // we clear only the flag of this interrupt and leave all other
+ // message box interrupts untouched
+ //
+ HAL_READ_UINT16(&flexcan->IFLAG, iflag);
+ HAL_WRITE_UINT16(&flexcan->IFLAG, (0x0001 << mbox));
+ info->tx_busy = false;
+
+ //
+ // On the mcf5272 there is no need to acknowledge internal
+ // interrupts, only external ones.
+ // cyg_drv_interrupt_acknowledge(vec);
+ //
+ return CYG_ISR_CALL_DSR;
+}
+
+
+//===========================================================================
+// Flexcan message box dsr
+//===========================================================================
+static void flexcan_mbox_tx_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
+{
+ can_channel *chan = (can_channel *)data;
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint16 imask;
+
+ //
+ // number of message box can be calculated from vector that caused
+ // interrupt - we pass this message box number as additional data to the
+ // callback
+ //
+ cyg_uint8 mbox = vec - info->isr_vec_mbox0;
+
+ //
+ // send next message
+ //
+ chan->callbacks->xmt_msg(chan, &mbox);
+
+ //
+ // reenable interrupts for the message box that caused the DSR to run
+ //
+ HAL_READ_UINT16(&flexcan->IMASK, imask);
+ HAL_WRITE_UINT16(&flexcan->IMASK, imask | (0x0001 << mbox));
+}
+
+
+//===========================================================================
+// START FLEXCAN MODUL
+//===========================================================================
+static void flexcan_start_chip(can_channel *chan)
+{
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+
+ cyg_uint16 tmp16;
+ HAL_READ_UINT16(&flexcan->CANMCR, tmp16);
+ HAL_WRITE_UINT16(&flexcan->CANMCR, tmp16
+ & ~(FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT));
+}
+
+
+//===========================================================================
+// SET ACCEPTANCE MASK
+//===========================================================================
+static void flexcan_set_acceptance_mask(cyg_uint16 *rxmask_reg, cyg_uint32 mask, cyg_uint8 ext)
+{
+ cyg_uint16 id;
+ //
+ // 32 bit access to RXMASK filters is broken so we use 16 Bit
+ // access here
+ //
+ if (ext != 0)
+ {
+ id = ((mask >> 13) & 0xFFE0); // set mask bits 18 - 28
+ id |= ((mask >> 15) & 0x7); // set mask bits 15 -17
+ HAL_WRITE_UINT16(&rxmask_reg[0], id);
+
+ id = (mask << 1) & 0xFFFE;
+ HAL_WRITE_UINT16(&rxmask_reg[1], id);
+ }
+ else
+ {
+ id = ((mask << 5) & 0xFFE0);
+ HAL_WRITE_UINT16(&rxmask_reg[0], id);
+ HAL_WRITE_UINT16(&rxmask_reg[1], 0xFFFF);
+ }
+
+}
+
+
+
+//===========================================================================
+// CONFIGURE MESSAGE BOX FOR TRANSMISSION
+//===========================================================================
+static bool flexcan_cfg_mbox_tx(flexcan_mbox *pmbox,
+ cyg_can_message *pmsg)
+{
+ cyg_uint16 id;
+
+ HAL_WRITE_UINT8(&pmbox->ctrlstat, MBOX_TXCODE_NOT_READY);
+
+ if (pmsg->ext != 0)
+ {
+ id = ((pmsg->id >> 13) & 0xFFE0); // setup id bits 18 - 28
+ id |= (MBOX_CFG_IDE | MBOX_CFG_SSR); // set SSR and IDE bit to 1
+ id |= ((pmsg->id >> 15) & 0x7); // set id bits 15 - 17
+ HAL_WRITE_UINT16(&pmbox->id_hi, id);
+
+ id = ((pmsg->id << 1) & 0xFFFE);
+
+ if (pmsg->rtr)
+ {
+ id |= MBOX_CFG_RTR_EXT;
+ }
+
+ HAL_WRITE_UINT16(&pmbox->id_lo, id);
+ }
+ else
+ {
+ id = ((pmsg->id << 5) & 0xFFE0);
+ if (pmsg->rtr)
+ {
+ id |= MBOX_CFG_RTR_STD; // set rtr bit for standard ID
+ }
+ HAL_WRITE_UINT16(&pmbox->id_hi, id);
+ HAL_WRITE_UINT16(&pmbox->id_lo, 0);
+ }
+
+ pmsg->dlc %= 9; // limit data length to 8 bytes
+
+ //
+ // Now copy data bytes into buffer and start transmission
+ //
+ HAL_WRITE_UINT8_VECTOR(&pmbox->data, pmsg->data, pmsg->dlc, 1);
+ HAL_WRITE_UINT8(&pmbox->ctrlstat, MBOX_TXCODE_TRANSMIT | pmsg->dlc);
+
+ return true;
+}
+
+
+
+//===========================================================================
+// CONFIGURE MESSAGE BOX FOR RECEPTION OF FRAMES
+//===========================================================================
+static void flexcan_cfg_mbox_rx(flexcan_mbox *pmbox,
+ cyg_uint32 canid,
+ cyg_uint8 ext)
+{
+ cyg_uint16 id;
+
+ HAL_WRITE_UINT8(&pmbox->ctrlstat, MBOX_RXCODE_NOT_ACTIVE);
+
+ if (ext != 0)
+ {
+ id = ((canid >> 13) & 0xFFE0); // setup id bits 18 - 28
+ id |= (MBOX_CFG_IDE | MBOX_CFG_SSR); // set SSR and IDE bit to 1
+ id |= ((canid >> 15) & 0x7); // set id bits 15 - 17
+ HAL_WRITE_UINT16(&pmbox->id_hi, id); // write ID high
+
+ id = ((canid << 1) & 0xFFFE);
+
+ HAL_WRITE_UINT16(&pmbox->id_lo, id);// write ID low
+ }
+ else
+ {
+ id = ((canid << 5) & 0xFFE0);
+
+ HAL_WRITE_UINT16(&pmbox->id_hi, id);
+ HAL_WRITE_UINT16(&pmbox->id_lo, 0);
+ }
+
+ HAL_WRITE_UINT8(&pmbox->ctrlstat, MBOX_RXCODE_EMPTY);
+}
+
+
+//===========================================================================
+// READ DATA FROM MESSAGE BOX
+//==========================================================================
+static void flexcan_read_from_mbox(can_channel *chan,
+ cyg_uint8 mbox,
+ cyg_can_event *pevent,
+ cyg_uint8 *ctrlstat)
+{
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ flexcan_mbox *pmbox = &flexcan->mbox[mbox];
+ cyg_can_message *pmsg = &pevent->msg;
+ cyg_uint16 id;
+ cyg_uint8 i;
+
+ HAL_READ_UINT8(&pmbox->ctrlstat, *ctrlstat); // this read will lock the mbox
+
+ //
+ // If message buffer is busy then it is now beeing filled with a new message
+ // This condition will be cleared within 20 cycles - wi simply do a 20 us
+ // delay here, that should be enougth
+ //
+ if (*ctrlstat & MBOX_RXCODE_BUSY)
+ {
+ HAL_DELAY_US(20);
+ }
+
+ pmsg->dlc = (*ctrlstat & MBOX_CFG_DLC_MASK); // store received data len
+ pmsg->rtr = 0;
+
+ HAL_READ_UINT16(&pmbox->id_hi, id); // read ID high
+
+ if (id & MBOX_CFG_IDE)
+ {
+ pmsg->ext = 1;
+ pmsg->id = (id & 0xFFE0) << 13;
+
+ HAL_READ_UINT16(&pmbox->id_lo, id);
+ pmsg->id |= (id & 0xFFFE) >> 1;
+ }
+ else
+ {
+ pmsg->ext = 0;
+ pmsg->id = (id & 0xFFE0) >> 5;
+ }
+
+ //
+ // now finally copy data
+ //
+ HAL_READ_UINT8_VECTOR(&pmbox->data, pmsg->data, pmsg->dlc, 1);
+
+ //
+ // now zero out the remaining bytes in can message in order
+ // to deliver a defined state
+ //
+ for (i = pmsg->dlc; i < 8; ++i)
+ {
+ pmsg->data[i] = 0;
+ }
+
+ //
+ // now mark this mbox as empty and read the free running timer
+ // to unlock this mbox
+ //
+ HAL_WRITE_UINT8(&pmbox->ctrlstat, MBOX_RXCODE_EMPTY);
+ HAL_READ_UINT16(&flexcan->TIMER, id);
+#ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP
+ pevent->timestamp = id;
+#endif
+}
+
+
+//===========================================================================
+// INIT CAN BAUD RATE
+//===========================================================================
+static bool flexcan_set_baud(can_channel *chan, cyg_uint16 baud)
+{
+ flexcan_info *info = (flexcan_info *)chan->dev_priv;
+ flexcan_regs *flexcan = (flexcan_regs *)info->base;
+ cyg_uint16 mcr_bck;
+ cyg_uint8 tmp8;
+ cyg_uint8 presdiv;
+ cyg_uint8 propseg;
+ cyg_uint8 pseg1_2;
+ cyg_uint16 baudrate = flexcan_baud_rates[baud];
+
+ //
+ // Get bit timings from HAL because bit timings depend on sysclock
+ //
+ HAL_MCF52xx_FLEXCAN_GET_BIT_TIMINGS(&baudrate, &presdiv, &propseg, &pseg1_2);
+
+ //
+ // return false if baudrate is not supported
+ //
+ if (0 == baudrate)
+ {
+ return false;
+ }
+
+ //
+ // For setting the bit timings we have to stop the flexcan modul
+ //
+ HAL_READ_UINT16(&flexcan->CANMCR, mcr_bck);
+ HAL_WRITE_UINT16(&flexcan->CANMCR, mcr_bck | FLEXCAN_MCR_HALT);
+
+ //
+ // now we setup bit timings
+ //
+ HAL_WRITE_UINT8(&flexcan->PRESDIV, presdiv);
+ HAL_READ_UINT8(&flexcan->CANCTRL1, tmp8);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL1, (tmp8 & 0xF8) | propseg);
+ HAL_READ_UINT8(&flexcan->CANCTRL2, tmp8);
+ HAL_WRITE_UINT8(&flexcan->CANCTRL2, (tmp8 & 0xC0) | pseg1_2);
+
+ //
+ // Now restore the previous state - if the modul was started then
+ // it will no be started again, if it was stopped, then it remains stopped
+ //
+ HAL_WRITE_UINT16(&flexcan->CANMCR, mcr_bck);
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+// end of can_mcf_flexcan.c
+
--- ecos_web_cvs/ecos/packages/ecos.db 2005-05-24 23:15:34.000000000 +0200
+++ ecos/ecos/packages/ecos.db 2005-05-26 22:49:00.000000000 +0200
@@ -94,6 +94,26 @@
serial devices."
}
+package CYGPKG_IO_CAN {
+ alias { "CAN device drivers" can io_can }
+ directory io/can
+ script io_can.cdl
+ description "
+ This package contains drivers for basic I/O services on
+ CAN devices."
+}
+
+package CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN {
+ alias { "MCF52xx FlexCAN device drivers"
+ devs_can_mcf52xx_flexcan mcf52xx_flexcan_serial_driver }
+ hardware
+ directory devs/can/m68k/mcf52xx
+ script can_mcf52xx.cdl
+ description "Generic CAN device driver for the on-chip
+ FlexCAN modules in MCF52xx ColdFire processors."
+}
+
+
package CYGPKG_IO_PCMCIA {
alias { "PCMCIA & Compact Flash support" pcmcia io_pcmcia cf }
directory io/pcmcia