summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/can/occan.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/can/occan.c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/occan.c1984
1 files changed, 0 insertions, 1984 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/can/occan.c b/c/src/lib/libbsp/sparc/shared/can/occan.c
deleted file mode 100644
index 2c0e49a2d5..0000000000
--- a/c/src/lib/libbsp/sparc/shared/can/occan.c
+++ /dev/null
@@ -1,1984 +0,0 @@
-/* OC_CAN driver
- *
- * COPYRIGHT (c) 2007.
- * Cobham Gaisler AB.
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
- */
-
-#include <rtems.h>
-#include <rtems/libio.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <bsp.h>
-#include <rtems/bspIo.h> /* printk */
-
-#include <drvmgr/drvmgr.h>
-#include <drvmgr/ambapp_bus.h>
-#include <bsp/occan.h>
-
-/* RTEMS -> ERRNO decoding table
-
-rtems_assoc_t errno_assoc[] = {
- { "OK", RTEMS_SUCCESSFUL, 0 },
- { "BUSY", RTEMS_RESOURCE_IN_USE, EBUSY },
- { "INVALID NAME", RTEMS_INVALID_NAME, EINVAL },
- { "NOT IMPLEMENTED", RTEMS_NOT_IMPLEMENTED, ENOSYS },
- { "TIMEOUT", RTEMS_TIMEOUT, ETIMEDOUT },
- { "NO MEMORY", RTEMS_NO_MEMORY, ENOMEM },
- { "NO DEVICE", RTEMS_UNSATISFIED, ENODEV },
- { "INVALID NUMBER", RTEMS_INVALID_NUMBER, EBADF},
- { "NOT RESOURCE OWNER", RTEMS_NOT_OWNER_OF_RESOURCE, EPERM},
- { "IO ERROR", RTEMS_IO_ERROR, EIO},
- { 0, 0, 0 },
-};
-
-*/
-
-/*
-#undef DEBUG
-#undef DEBUG_EXTRA
-#undef DEBUG_PRINT_REGMAP
-*/
-
-/* default to byte regs */
-#ifndef OCCAN_WORD_REGS
- #define OCCAN_BYTE_REGS
-#else
- #undef OCCAN_BYTE_REGS
-#endif
-
-/* Enable Fixup code older OCCAN with a TX IRQ-FLAG bug */
-#define OCCAN_TX_IRQ_FLAG_FIXUP 1
-
-#define OCCAN_WORD_REG_OFS 0x80
-#define OCCAN_NCORE_OFS 0x100
-#define DEFAULT_CLKDIV 0x7
-#define DEFAULT_EXTENDED_MODE 1
-#define DEFAULT_RX_FIFO_LEN 64
-#define DEFAULT_TX_FIFO_LEN 64
-
-/* not implemented yet */
-#undef REDUNDANT_CHANNELS
-
-/* Define common debug macros */
-#ifdef DEBUG
- #define DBG(fmt, vargs...) printk(fmt, ## vargs )
-#else
- #define DBG(fmt, vargs...)
-#endif
-
-/* Spin locks mapped via rtems_interrupt_lock_* API: */
-#define SPIN_DECLARE(lock) RTEMS_INTERRUPT_LOCK_MEMBER(lock)
-#define SPIN_INIT(lock, name) rtems_interrupt_lock_initialize(lock, name)
-#define SPIN_LOCK(lock, level) rtems_interrupt_lock_acquire_isr(lock, &level)
-#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_lock_acquire(lock, &level)
-#define SPIN_UNLOCK(lock, level) rtems_interrupt_lock_release_isr(lock, &level)
-#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_lock_release(lock, &level)
-#define SPIN_IRQFLAGS(k) rtems_interrupt_lock_context k
-#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k)
-
-/* fifo interface */
-typedef struct {
- int cnt;
- int ovcnt; /* overwrite count */
- int full; /* 1 = base contain cnt CANMsgs, tail==head */
- CANMsg *tail, *head;
- CANMsg *base;
- char fifoarea[0];
-} occan_fifo;
-
-/* PELICAN */
-
-typedef struct {
- unsigned char
- mode,
- cmd,
- status,
- intflags,
- inten,
- resv0,
- bustim0,
- bustim1,
- unused0[2],
- resv1,
- arbcode,
- errcode,
- errwarn,
- rx_err_cnt,
- tx_err_cnt,
- rx_fi_xff; /* this is also acceptance code 0 in reset mode */
- union{
- struct {
- unsigned char id[2];
- unsigned char data[8];
- unsigned char next_in_fifo[2];
- } rx_sff;
- struct {
- unsigned char id[4];
- unsigned char data[8];
- } rx_eff;
- struct {
- unsigned char id[2];
- unsigned char data[8];
- unsigned char unused[2];
- } tx_sff;
- struct {
- unsigned char id[4];
- unsigned char data[8];
- } tx_eff;
- struct {
- unsigned char code[3];
- unsigned char mask[4];
- } rst_accept;
- } msg;
- unsigned char rx_msg_cnt;
- unsigned char unused1;
- unsigned char clkdiv;
-} pelican8_regs;
-
-typedef struct {
- unsigned char
- mode, unused0[3],
- cmd, unused1[3],
- status, unused2[3],
- intflags, unused3[3],
- inten, unused4[3],
- resv0, unused5[3],
- bustim0, unused6[3],
- bustim1, unused7[3],
- unused8[8],
- resv1,unused9[3],
- arbcode,unused10[3],
- errcode,unused11[3],
- errwarn,unused12[3],
- rx_err_cnt,unused13[3],
- tx_err_cnt,unused14[3],
- rx_fi_xff, unused15[3]; /* this is also acceptance code 0 in reset mode */
- /* make sure to use pointers when writing (byte access) to these registers */
- union{
- struct {
- unsigned int id[2];
- unsigned int data[8];
- unsigned int next_in_fifo[2];
- } rx_sff;
- struct {
- unsigned int id[4];
- unsigned int data[8];
- } rx_eff;
- struct {
- unsigned int id[2];
- unsigned int data[8];
- } tx_sff;
- struct {
- unsigned int id[4];
- unsigned int data[8];
- } tx_eff;
- struct {
- unsigned int code[3];
- unsigned int mask[4];
- } rst_accept;
- } msg;
- unsigned char rx_msg_cnt,unused16[3];
- unsigned char unused17[4];
- unsigned char clkdiv,unused18[3];
-} pelican32_regs;
-
-#ifdef OCCAN_BYTE_REGS
-#define pelican_regs pelican8_regs
-#else
-#define pelican_regs pelican32_regs
-#endif
-
-
-#define MAX_TSEG2 7
-#define MAX_TSEG1 15
-
-#if 0
-typedef struct {
- unsigned char brp;
- unsigned char sjw;
- unsigned char tseg1;
- unsigned char tseg2;
- unsigned char sam;
-} occan_speed_regs;
-#endif
-typedef struct {
- unsigned char btr0;
- unsigned char btr1;
-} occan_speed_regs;
-
-typedef struct {
- struct drvmgr_dev *dev;
- char devName[32];
- SPIN_DECLARE(devlock);
-
- /* hardware shortcuts */
- pelican_regs *regs;
- int byte_regs;
- int irq;
- occan_speed_regs timing;
- int channel; /* 0=default, 1=second bus */
- int single_mode;
- unsigned int sys_freq_hz;
-
- /* driver state */
- rtems_id devsem;
- rtems_id txsem;
- rtems_id rxsem;
- int open;
- int started;
- int rxblk;
- int txblk;
- int sending;
- unsigned int status;
- occan_stats stats;
-
- /* rx&tx fifos */
- occan_fifo *rxfifo;
- occan_fifo *txfifo;
-
- /* Config */
- unsigned int speed; /* speed in HZ */
- unsigned char acode[4];
- unsigned char amask[4];
-} occan_priv;
-
-/********** FIFO INTERFACE **********/
-static void occan_fifo_put(occan_fifo *fifo);
-static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force);
-static occan_fifo *occan_fifo_create(int cnt);
-static void occan_fifo_free(occan_fifo *fifo);
-static int occan_fifo_full(occan_fifo *fifo);
-static int occan_fifo_empty(occan_fifo *fifo);
-static void occan_fifo_get(occan_fifo *fifo);
-static CANMsg *occan_fifo_claim_get(occan_fifo *fifo);
-static void occan_fifo_clr(occan_fifo *fifo);
-
-/**** Hardware related Interface ****/
-static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result);
-static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing);
-static void pelican_init(occan_priv *priv);
-static void pelican_open(occan_priv *priv);
-static int pelican_start(occan_priv *priv);
-static void pelican_stop(occan_priv *priv);
-static int pelican_send(occan_priv *can, CANMsg *msg);
-static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask);
-void occan_interrupt(void *arg);
-#ifdef DEBUG_PRINT_REGMAP
-static void pelican_regadr_print(pelican_regs *regs);
-#endif
-
-/***** Driver related interface *****/
-static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver occan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver occan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver occan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
-static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
-
-#define OCCAN_DRIVER_TABLE_ENTRY { occan_initialize, occan_open, occan_close, occan_read, occan_write, occan_ioctl }
-static rtems_driver_address_table occan_driver = OCCAN_DRIVER_TABLE_ENTRY;
-
-
-/* Read byte bypassing */
-
-
-/* Bypass cache */
-#define READ_REG(priv, address) occan_reg_read(priv, (unsigned int)address)
-#define WRITE_REG(priv, address, data) occan_reg_write(priv, (unsigned int)address, data)
-
-static unsigned int occan_reg_read(occan_priv *priv, unsigned int address)
-{
- unsigned int adr;
- if ( priv->byte_regs ) {
- adr = address;
- } else {
- /* Word accessed registers */
- adr = (address & (~0x7f)) | ((address & 0x7f)<<2);
- }
- return *(volatile unsigned char *)adr;
-}
-
-static void occan_reg_write(
- occan_priv *priv,
- unsigned int address,
- unsigned char value)
-{
- unsigned int adr;
- if ( priv->byte_regs ) {
- adr = address;
- } else {
- /* Word accessed registers */
- adr = (address & (~0x7f)) | ((address & 0x7f)<<2);
- }
- *(volatile unsigned char *)adr = value;;
-}
-
-/* Mode register bit definitions */
-#define PELICAN_MOD_RESET 0x1
-#define PELICAN_MOD_LISTEN 0x2
-#define PELICAN_MOD_SELFTEST 0x4
-#define PELICAN_MOD_ACCEPT 0x8
-
-/* Command register bit definitions */
-#define PELICAN_CMD_TXREQ 0x1
-#define PELICAN_CMD_ABORT 0x2
-#define PELICAN_CMD_RELRXBUF 0x4
-#define PELICAN_CMD_CLRDOVR 0x8
-#define PELICAN_CMD_SELFRXRQ 0x10
-
-/* Status register bit definitions */
-#define PELICAN_STAT_RXBUF 0x1
-#define PELICAN_STAT_DOVR 0x2
-#define PELICAN_STAT_TXBUF 0x4
-#define PELICAN_STAT_TXOK 0x8
-#define PELICAN_STAT_RX 0x10
-#define PELICAN_STAT_TX 0x20
-#define PELICAN_STAT_ERR 0x40
-#define PELICAN_STAT_BUS 0x80
-
-/* Interrupt register bit definitions */
-#define PELICAN_IF_RX 0x1
-#define PELICAN_IF_TX 0x2
-#define PELICAN_IF_ERRW 0x4
-#define PELICAN_IF_DOVR 0x8
-#define PELICAN_IF_ERRP 0x20
-#define PELICAN_IF_ARB 0x40
-#define PELICAN_IF_BUS 0x80
-
-/* Interrupt Enable register bit definitions */
-#define PELICAN_IE_RX 0x1
-#define PELICAN_IE_TX 0x2
-#define PELICAN_IE_ERRW 0x4
-#define PELICAN_IE_DOVR 0x8
-#define PELICAN_IE_ERRP 0x20
-#define PELICAN_IE_ARB 0x40
-#define PELICAN_IE_BUS 0x80
-
-/* Arbitration lost capture register bit definitions */
-#define PELICAN_ARB_BITS 0x1f
-
-/* register bit definitions */
-#define PELICAN_ECC_CODE_BIT 0x00
-#define PELICAN_ECC_CODE_FORM 0x40
-#define PELICAN_ECC_CODE_STUFF 0x80
-#define PELICAN_ECC_CODE_OTHER 0xc0
-#define PELICAN_ECC_CODE 0xc0
-
-#define PELICAN_ECC_DIR 0x20
-#define PELICAN_ECC_SEG 0x1f
-
-/* Clock divider register bit definitions */
-#define PELICAN_CDR_DIV 0x7
-#define PELICAN_CDR_OFF 0x8
-#define PELICAN_CDR_MODE 0x80
-#define PELICAN_CDR_MODE_PELICAN 0x80
-#define PELICAN_CDR_MODE_BITS 7
-#define PELICAN_CDR_MODE_BASICAN 0x00
-
-
-/* register bit definitions */
-#define OCCAN_BUSTIM_SJW 0xc0
-#define OCCAN_BUSTIM_BRP 0x3f
-#define OCCAN_BUSTIM_SJW_BIT 6
-
-#define OCCAN_BUSTIM_SAM 0x80
-#define OCCAN_BUSTIM_TSEG2 0x70
-#define OCCAN_BUSTIM_TSEG2_BIT 4
-#define OCCAN_BUSTIM_TSEG1 0x0f
-
-/* register bit definitions */
-/*
-#define PELICAN_S_ 0x1
-#define PELICAN_S_ 0x2
-#define PELICAN_S_ 0x4
-#define PELICAN_S_ 0x8
-#define PELICAN_S_ 0x10
-#define PELICAN_S_ 0x20
-#define PELICAN_S_ 0x40
-#define PELICAN_S_ 0x80
-*/
-
-static int occan_driver_io_registered = 0;
-static rtems_device_major_number occan_driver_io_major = 0;
-
-/******************* Driver manager interface ***********************/
-
-/* Driver prototypes */
-int occan_register_io(rtems_device_major_number *m);
-int occan_device_init(occan_priv *pDev);
-
-int occan_init2(struct drvmgr_dev *dev);
-int occan_init3(struct drvmgr_dev *dev);
-
-struct drvmgr_drv_ops occan_ops =
-{
- .init = {NULL, occan_init2, occan_init3, NULL},
- .remove = NULL,
- .info = NULL
-};
-
-struct amba_dev_id occan_ids[] =
-{
- {VENDOR_GAISLER, GAISLER_CANAHB},
- {0, 0} /* Mark end of table */
-};
-
-struct amba_drv_info occan_drv_info =
-{
- {
- DRVMGR_OBJ_DRV, /* Driver */
- NULL, /* Next driver */
- NULL, /* Device list */
- DRIVER_AMBAPP_GAISLER_OCCAN_ID, /* Driver ID */
- "OCCAN_DRV", /* Driver Name */
- DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
- &occan_ops,
- NULL, /* Funcs */
- 0, /* No devices yet */
- 0,
- },
- &occan_ids[0]
-};
-
-void occan_register_drv (void)
-{
- DBG("Registering OCCAN driver\n");
- drvmgr_drv_register(&occan_drv_info.general);
-}
-
-int occan_init2(struct drvmgr_dev *dev)
-{
- occan_priv *priv;
-
- DBG("OCCAN[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
- priv = dev->priv = malloc(sizeof(occan_priv));
- if ( !priv )
- return DRVMGR_NOMEM;
- memset(priv, 0, sizeof(*priv));
- priv->dev = dev;
-
- return DRVMGR_OK;
-}
-
-int occan_init3(struct drvmgr_dev *dev)
-{
- occan_priv *priv;
- char prefix[32];
- rtems_status_code status;
-
- priv = dev->priv;
-
- /* Do initialization */
-
- if ( occan_driver_io_registered == 0) {
- /* Register the I/O driver only once for all cores */
- if ( occan_register_io(&occan_driver_io_major) ) {
- /* Failed to register I/O driver */
- dev->priv = NULL;
- return DRVMGR_FAIL;
- }
-
- occan_driver_io_registered = 1;
- }
-
- /* I/O system registered and initialized
- * Now we take care of device initialization.
- */
-
- if ( occan_device_init(priv) ) {
- return DRVMGR_FAIL;
- }
-
- /* Get Filesystem name prefix */
- prefix[0] = '\0';
- if ( drvmgr_get_dev_prefix(dev, prefix) ) {
- /* Failed to get prefix, make sure of a unique FS name
- * by using the driver minor.
- */
- sprintf(priv->devName, "/dev/occan%d", dev->minor_drv);
- } else {
- /* Got special prefix, this means we have a bus prefix
- * And we should use our "bus minor"
- */
- sprintf(priv->devName, "/dev/%soccan%d", prefix, dev->minor_bus);
- }
-
- /* Register Device */
- DBG("OCCAN[%d]: Registering %s\n", dev->minor_drv, priv->devName);
- status = rtems_io_register_name(priv->devName, occan_driver_io_major, dev->minor_drv);
- if (status != RTEMS_SUCCESSFUL) {
- return DRVMGR_FAIL;
- }
-
- return DRVMGR_OK;
-}
-
-/******************* Driver Implementation ***********************/
-
-int occan_register_io(rtems_device_major_number *m)
-{
- rtems_status_code r;
-
- if ((r = rtems_io_register_driver(0, &occan_driver, m)) == RTEMS_SUCCESSFUL) {
- DBG("OCCAN driver successfully registered, major: %d\n", *m);
- } else {
- switch(r) {
- case RTEMS_TOO_MANY:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
- return -1;
- case RTEMS_INVALID_NUMBER:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
- return -1;
- case RTEMS_RESOURCE_IN_USE:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
- return -1;
- default:
- printk("OCCAN rtems_io_register_driver failed\n");
- return -1;
- }
- }
- return 0;
-}
-
-int occan_device_init(occan_priv *pDev)
-{
- struct amba_dev_info *ambadev;
- struct ambapp_core *pnpinfo;
- rtems_status_code status;
- int minor;
-
- /* Get device information from AMBA PnP information */
- ambadev = (struct amba_dev_info *)pDev->dev->businfo;
- if ( ambadev == NULL ) {
- return -1;
- }
- pnpinfo = &ambadev->info;
- pDev->irq = pnpinfo->irq;
- pDev->regs = (pelican_regs *)(pnpinfo->ahb_slv->start[0] + OCCAN_NCORE_OFS*pnpinfo->index);
- pDev->byte_regs = 1;
- minor = pDev->dev->minor_drv;
-
- /* Get frequency in Hz */
- if ( drvmgr_freq_get(pDev->dev, DEV_AHB_SLV, &pDev->sys_freq_hz) ) {
- return -1;
- }
-
- DBG("OCCAN frequency: %d Hz\n", pDev->sys_freq_hz);
-
- /* initialize software */
- pDev->open = 0;
- pDev->started = 0; /* Needed for spurious interrupts */
- pDev->rxfifo = NULL;
- pDev->txfifo = NULL;
- status = rtems_semaphore_create(
- rtems_build_name('C', 'd', 'v', '0'+minor),
- 1,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->devsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN[%d]: Failed to create dev semaphore, (%d)\n\r",minor, status);
- return RTEMS_UNSATISFIED;
- }
- status = rtems_semaphore_create(
- rtems_build_name('C', 't', 'x', '0'+minor),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->txsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN[%d]: Failed to create tx semaphore, (%d)\n\r",minor, status);
- return RTEMS_UNSATISFIED;
- }
- status = rtems_semaphore_create(
- rtems_build_name('C', 'r', 'x', '0'+minor),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->rxsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN[%d]: Failed to create rx semaphore, (%d)\n\r",minor, status);
- return RTEMS_UNSATISFIED;
- }
-
- /* hardware init/reset */
- pelican_init(pDev);
-
-#ifdef DEBUG_PRINT_REGMAP
- pelican_regadr_print(pDev->regs);
-#endif
-
- return 0;
-}
-
-
-#ifdef DEBUG
-static void pelican_regs_print(occan_priv *pDev){
- pelican_regs *regs = pDev->regs;
- printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
- printk(" MODE: 0x%02x\n\r",READ_REG(pDev, &regs->mode));
- printk(" CMD: 0x%02x\n\r",READ_REG(pDev, &regs->cmd));
- printk(" STATUS: 0x%02x\n\r",READ_REG(pDev, &regs->status));
- /*printk(" INTFLG: 0x%02x\n\r",READ_REG(pDev, &regs->intflags));*/
- printk(" INTEN: 0x%02x\n\r",READ_REG(pDev, &regs->inten));
- printk(" BTR0: 0x%02x\n\r",READ_REG(pDev, &regs->bustim0));
- printk(" BTR1: 0x%02x\n\r",READ_REG(pDev, &regs->bustim1));
- printk(" ARBCODE: 0x%02x\n\r",READ_REG(pDev, &regs->arbcode));
- printk(" ERRCODE: 0x%02x\n\r",READ_REG(pDev, &regs->errcode));
- printk(" ERRWARN: 0x%02x\n\r",READ_REG(pDev, &regs->errwarn));
- printk(" RX_ERR_CNT: 0x%02x\n\r",READ_REG(pDev, &regs->rx_err_cnt));
- printk(" TX_ERR_CNT: 0x%02x\n\r",READ_REG(pDev, &regs->tx_err_cnt));
- if ( READ_REG(pDev, &regs->mode) & PELICAN_MOD_RESET ){
- /* in reset mode it is possible to read acceptance filters */
- printk(" ACR0: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->rx_fi_xff),&regs->rx_fi_xff);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.code[0]),(unsigned int)&regs->msg.rst_accept.code[0]);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.code[1]),(unsigned int)&regs->msg.rst_accept.code[1]);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.code[2]),(unsigned int)&regs->msg.rst_accept.code[2]);
- printk(" AMR0: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.mask[0]),(unsigned int)&regs->msg.rst_accept.mask[0]);
- printk(" AMR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.mask[1]),(unsigned int)&regs->msg.rst_accept.mask[1]);
- printk(" AMR2: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.mask[2]),(unsigned int)&regs->msg.rst_accept.mask[2]);
- printk(" AMR3: 0x%02x (0x%lx)\n\r",READ_REG(pDev, &regs->msg.rst_accept.mask[3]),(unsigned int)&regs->msg.rst_accept.mask[3]);
-
- }else{
- printk(" RXFI_XFF: 0x%02x\n\r",READ_REG(pDev, &regs->rx_fi_xff));
- }
- printk(" RX_MSG_CNT: 0x%02x\n\r",READ_REG(pDev, &regs->rx_msg_cnt));
- printk(" CLKDIV: 0x%02x\n\r",READ_REG(pDev, &regs->clkdiv));
- printk("-------------------\n\r");
-}
-#endif
-
-#ifdef DEBUG_PRINT_REGMAP
-static void pelican_regadr_print(pelican_regs *regs){
- printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
- printk(" MODE: 0x%lx\n\r",(unsigned int)&regs->mode);
- printk(" CMD: 0x%lx\n\r",(unsigned int)&regs->cmd);
- printk(" STATUS: 0x%lx\n\r",(unsigned int)&regs->status);
- /*printk(" INTFLG: 0x%lx\n\r",&regs->intflags);*/
- printk(" INTEN: 0x%lx\n\r",(unsigned int)&regs->inten);
- printk(" BTR0: 0x%lx\n\r",(unsigned int)&regs->bustim0);
- printk(" BTR1: 0x%lx\n\r",(unsigned int)&regs->bustim1);
- printk(" ARBCODE: 0x%lx\n\r",(unsigned int)&regs->arbcode);
- printk(" ERRCODE: 0x%lx\n\r",(unsigned int)&regs->errcode);
- printk(" ERRWARN: 0x%lx\n\r",(unsigned int)&regs->errwarn);
- printk(" RX_ERR_CNT: 0x%lx\n\r",(unsigned int)&regs->rx_err_cnt);
- printk(" TX_ERR_CNT: 0x%lx\n\r",(unsigned int)&regs->tx_err_cnt);
-
- /* in reset mode it is possible to read acceptance filters */
- printk(" RXFI_XFF: 0x%lx\n\r",(unsigned int)&regs->rx_fi_xff);
-
- /* reset registers */
- printk(" ACR0: 0x%lx\n\r",(unsigned int)&regs->rx_fi_xff);
- printk(" ACR1: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[0]);
- printk(" ACR2: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[1]);
- printk(" ACR3: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.code[2]);
- printk(" AMR0: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[0]);
- printk(" AMR1: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[1]);
- printk(" AMR2: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[2]);
- printk(" AMR3: 0x%lx\n\r",(unsigned int)&regs->msg.rst_accept.mask[3]);
-
- /* TX Extended */
- printk(" EFFTX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[0]);
- printk(" EFFTX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[1]);
- printk(" EFFTX_ID[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[2]);
- printk(" EFFTX_ID[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.id[3]);
-
- printk(" EFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[0]);
- printk(" EFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[1]);
- printk(" EFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[2]);
- printk(" EFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[3]);
- printk(" EFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[4]);
- printk(" EFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[5]);
- printk(" EFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[6]);
- printk(" EFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_eff.data[7]);
-
- /* RX Extended */
- printk(" EFFRX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[0]);
- printk(" EFFRX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[1]);
- printk(" EFFRX_ID[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[2]);
- printk(" EFFRX_ID[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.id[3]);
-
- printk(" EFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[0]);
- printk(" EFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[1]);
- printk(" EFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[2]);
- printk(" EFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[3]);
- printk(" EFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[4]);
- printk(" EFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[5]);
- printk(" EFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[6]);
- printk(" EFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_eff.data[7]);
-
-
- /* RX Extended */
- printk(" SFFRX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.id[0]);
- printk(" SFFRX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.id[1]);
-
- printk(" SFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[0]);
- printk(" SFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[1]);
- printk(" SFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[2]);
- printk(" SFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[3]);
- printk(" SFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[4]);
- printk(" SFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[5]);
- printk(" SFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[6]);
- printk(" SFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.rx_sff.data[7]);
-
- /* TX Extended */
- printk(" SFFTX_ID[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.id[0]);
- printk(" SFFTX_ID[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.id[1]);
-
- printk(" SFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[0]);
- printk(" SFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[1]);
- printk(" SFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[2]);
- printk(" SFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[3]);
- printk(" SFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[4]);
- printk(" SFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[5]);
- printk(" SFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[6]);
- printk(" SFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)&regs->msg.tx_sff.data[7]);
-
- printk(" RX_MSG_CNT: 0x%lx\n\r",(unsigned int)&regs->rx_msg_cnt);
- printk(" CLKDIV: 0x%lx\n\r",(unsigned int)&regs->clkdiv);
- printk("-------------------\n\r");
-}
-#endif
-
-#ifdef DEBUG
-static void occan_stat_print(occan_stats *stats){
- printk("----Stats----\n\r");
- printk("rx_msgs: %d\n\r",stats->rx_msgs);
- printk("tx_msgs: %d\n\r",stats->tx_msgs);
- printk("err_warn: %d\n\r",stats->err_warn);
- printk("err_dovr: %d\n\r",stats->err_dovr);
- printk("err_errp: %d\n\r",stats->err_errp);
- printk("err_arb: %d\n\r",stats->err_arb);
- printk("err_bus: %d\n\r",stats->err_bus);
- printk("Int cnt: %d\n\r",stats->ints);
- printk("tx_buf_err: %d\n\r",stats->tx_buf_error);
- printk("-------------\n\r");
-}
-#endif
-
-static void pelican_init(occan_priv *priv){
- /* Reset core */
- WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET);
-
- /* wait for core to reset complete */
- /*usleep(1);*/
-}
-
-static void pelican_open(occan_priv *priv){
- int ret;
-
- /* Set defaults */
- priv->speed = OCCAN_SPEED_250K;
-
- /* set acceptance filters to accept all messages */
- priv->acode[0] = 0;
- priv->acode[1] = 0;
- priv->acode[2] = 0;
- priv->acode[3] = 0;
- priv->amask[0] = 0xff;
- priv->amask[1] = 0xff;
- priv->amask[2] = 0xff;
- priv->amask[3] = 0xff;
-
- /* Set clock divider to extended mode, clkdiv not connected
- */
- WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
-
- ret = occan_calc_speedregs(priv->sys_freq_hz,priv->speed,&priv->timing);
- if ( ret ){
- /* failed to set speed for this system freq, try with 50K instead */
- priv->speed = OCCAN_SPEED_50K;
- occan_calc_speedregs(priv->sys_freq_hz, priv->speed,
- &priv->timing);
- }
-
- /* disable all interrupts */
- WRITE_REG(priv, &priv->regs->inten, 0);
-
- /* clear pending interrupts by reading */
- READ_REG(priv, &priv->regs->intflags);
-}
-
-static int pelican_start(occan_priv *priv){
- /* Start HW communication */
-
- if ( !priv->rxfifo || !priv->txfifo )
- return -1;
-
- /* In case we were started before and stopped we
- * should empty the TX fifo or try to resend those
- * messages. We make it simple...
- */
- occan_fifo_clr(priv->txfifo);
-
- /* Clear status bits */
- priv->status = 0;
- priv->sending = 0;
-
- /* clear pending interrupts */
- READ_REG(priv, &priv->regs->intflags);
-
- /* clear error counters */
- WRITE_REG(priv, &priv->regs->rx_err_cnt, 0);
- WRITE_REG(priv, &priv->regs->tx_err_cnt, 0);
-
-#ifdef REDUNDANT_CHANNELS
- if ( (priv->channel == 0) || (priv->channel >= REDUNDANT_CHANNELS) ){
- /* Select the first (default) channel */
- OCCAN_SET_CHANNEL(priv,0);
- }else{
- /* set gpio bit, or something */
- OCCAN_SET_CHANNEL(priv,priv->channel);
- }
-#endif
- /* set the speed regs of the CAN core */
- occan_set_speedregs(priv,&priv->timing);
-
- DBG("OCCAN: start: set timing regs btr0: 0x%x, btr1: 0x%x\n\r",
- READ_REG(priv, &priv->regs->bustim0),
- READ_REG(priv, &priv->regs->bustim1));
-
- /* Set default acceptance filter */
- pelican_set_accept(priv,priv->acode,priv->amask);
-
- /* Nothing can fail from here, this must be set before interrupts are
- * enabled */
- priv->started = 1;
-
- /* turn on interrupts */
- WRITE_REG(priv, &priv->regs->inten,
- PELICAN_IE_RX | PELICAN_IE_TX | PELICAN_IE_ERRW |
- PELICAN_IE_ERRP | PELICAN_IE_BUS);
-#ifdef DEBUG
- /* print setup before starting */
- pelican_regs_print(priv->regs);
- occan_stat_print(&priv->stats);
-#endif
-
- /* core already in reset mode,
- * ¤ Exit reset mode
- * ¤ Enter Single/Dual mode filtering.
- */
- WRITE_REG(priv, &priv->regs->mode, (priv->single_mode << 3));
-
- /* Register interrupt routine and unmask IRQ at IRQ controller */
- drvmgr_interrupt_register(priv->dev, 0, "occan", occan_interrupt, priv);
-
- return 0;
-}
-
-static void pelican_stop(occan_priv *priv)
-{
- /* stop HW */
-
- drvmgr_interrupt_unregister(priv->dev, 0, occan_interrupt, priv);
-
-#ifdef DEBUG
- /* print setup before stopping */
- pelican_regs_print(priv->regs);
- occan_stat_print(&priv->stats);
-#endif
-
- /* put core in reset mode */
- WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET);
-
- /* turn off interrupts */
- WRITE_REG(priv, &priv->regs->inten, 0);
-
- priv->status |= OCCAN_STATUS_RESET;
-}
-
-static inline int pelican_tx_ready(occan_priv *can)
-{
- unsigned char status;
- pelican_regs *regs = can->regs;
-
- /* is there room in send buffer? */
- status = READ_REG(can, &regs->status);
- if ( !(status & PELICAN_STAT_TXBUF) ) {
- /* tx fifo taken, we have to wait */
- return 0;
- }
-
- return 1;
-}
-
-/* Try to send message "msg", if hardware txfifo is
- * full, then -1 is returned.
- *
- * Be sure to have disabled CAN interrupts when
- * entering this function.
- */
-static int pelican_send(occan_priv *can, CANMsg *msg){
- unsigned char tmp;
- pelican_regs *regs = can->regs;
-
- /* is there room in send buffer? */
- if ( !pelican_tx_ready(can) ) {
- /* tx fifo taken, we have to wait */
- return -1;
- }
-
- tmp = msg->len & 0xf;
- if ( msg->rtr )
- tmp |= 0x40;
-
- if ( msg->extended ){
- /* Extended Frame */
- WRITE_REG(can, &regs->rx_fi_xff, 0x80 | tmp);
- WRITE_REG(can, &regs->msg.tx_eff.id[0],(msg->id >> (5+8+8)) & 0xff);
- WRITE_REG(can, &regs->msg.tx_eff.id[1],(msg->id >> (5+8)) & 0xff);
- WRITE_REG(can, &regs->msg.tx_eff.id[2],(msg->id >> (5)) & 0xff);
- WRITE_REG(can, &regs->msg.tx_eff.id[3],(msg->id << 3) & 0xf8);
- tmp = msg->len;
- while(tmp--){
- WRITE_REG(can, &regs->msg.tx_eff.data[tmp], msg->data[tmp]);
- }
- }else{
- /* Standard Frame */
- WRITE_REG(can, &regs->rx_fi_xff, tmp);
- WRITE_REG(can, &regs->msg.tx_sff.id[0],(msg->id >> 3) & 0xff);
- WRITE_REG(can, &regs->msg.tx_sff.id[1],(msg->id << 5) & 0xe0);
- tmp = msg->len;
- while(tmp--){
- WRITE_REG(can, &regs->msg.tx_sff.data[tmp],msg->data[tmp]);
- }
- }
-
- /* let HW know of new message */
- if ( msg->sshot ){
- WRITE_REG(can, &regs->cmd, PELICAN_CMD_TXREQ | PELICAN_CMD_ABORT);
- }else{
- /* normal case -- try resend until sent */
- WRITE_REG(can, &regs->cmd, PELICAN_CMD_TXREQ);
- }
-
- return 0;
-}
-
-
-static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask)
-{
- unsigned char *acode0, *acode1, *acode2, *acode3;
- unsigned char *amask0, *amask1, *amask2, *amask3;
-
- acode0 = &priv->regs->rx_fi_xff;
- acode1 = (unsigned char *)&priv->regs->msg.rst_accept.code[0];
- acode2 = (unsigned char *)&priv->regs->msg.rst_accept.code[1];
- acode3 = (unsigned char *)&priv->regs->msg.rst_accept.code[2];
-
- amask0 = (unsigned char *)&priv->regs->msg.rst_accept.mask[0];
- amask1 = (unsigned char *)&priv->regs->msg.rst_accept.mask[1];
- amask2 = (unsigned char *)&priv->regs->msg.rst_accept.mask[2];
- amask3 = (unsigned char *)&priv->regs->msg.rst_accept.mask[3];
-
- /* Set new mask & code */
- WRITE_REG(priv, acode0, acode[0]);
- WRITE_REG(priv, acode1, acode[1]);
- WRITE_REG(priv, acode2, acode[2]);
- WRITE_REG(priv, acode3, acode[3]);
-
- WRITE_REG(priv, amask0, amask[0]);
- WRITE_REG(priv, amask1, amask[1]);
- WRITE_REG(priv, amask2, amask[2]);
- WRITE_REG(priv, amask3, amask[3]);
-}
-
-
-/* This function calculates BTR0 and BTR1 values for a given bitrate.
- *
- * Set communication parameters.
- * \param clock_hz OC_CAN Core frequency in Hz.
- * \param rate Requested baud rate in bits/second.
- * \param result Pointer to where resulting BTRs will be stored.
- * \return zero if successful to calculate a baud rate.
- */
-static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result)
-{
- int best_error = 1000000000;
- int error;
- int best_tseg=0, best_brp=0, brp=0;
- int tseg=0, tseg1=0, tseg2=0;
- int sjw = 0;
- int clock = clock_hz / 2;
- int sampl_pt = 90;
-
- if ( (rate<5000) || (rate>1000000) ){
- /* invalid speed mode */
- return -1;
- }
-
- /* find best match, return -2 if no good reg
- * combination is available for this frequency */
-
- /* some heuristic specials */
- if (rate > ((1000000 + 500000) / 2))
- sampl_pt = 75;
-
- if (rate < ((12500 + 10000) / 2))
- sampl_pt = 75;
-
- if (rate < ((100000 + 125000) / 2))
- sjw = 1;
-
- /* tseg even = round down, odd = round up */
- for (tseg = (0 + 0 + 2) * 2;
- tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
- tseg++)
- {
- brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
- if ((brp == 0) || (brp > 64))
- continue;
-
- error = rate - clock / (brp * (1 + tseg / 2));
- if (error < 0)
- {
- error = -error;
- }
-
- if (error <= best_error)
- {
- best_error = error;
- best_tseg = tseg/2;
- best_brp = brp-1;
- }
- }
-
- if (best_error && (rate / best_error < 10))
- {
- printk("OCCAN: bitrate %d is not possible with %d Hz clock\n\r",rate, clock);
- return -2;
- }else if ( !result )
- return 0; /* nothing to store result in, but a valid bitrate can be calculated */
-
- tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
-
- if (tseg2 < 0)
- {
- tseg2 = 0;
- }
-
- if (tseg2 > MAX_TSEG2)
- {
- tseg2 = MAX_TSEG2;
- }
-
- tseg1 = best_tseg - tseg2 - 2;
-
- if (tseg1 > MAX_TSEG1)
- {
- tseg1 = MAX_TSEG1;
- tseg2 = best_tseg - tseg1 - 2;
- }
-
- result->btr0 = (sjw<<OCCAN_BUSTIM_SJW_BIT) | (best_brp&OCCAN_BUSTIM_BRP);
- result->btr1 = (0<<7) | (tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | tseg1;
-
- return 0;
-}
-
-static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
-{
- if ( !timing || !priv || !priv->regs)
- return -1;
-
- WRITE_REG(priv, &priv->regs->bustim0, timing->btr0);
- WRITE_REG(priv, &priv->regs->bustim1, timing->btr1);
-
- return 0;
-}
-
-static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg)
-{
- return RTEMS_SUCCESSFUL;
-}
-
-static rtems_device_driver occan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
-{
- occan_priv *can;
- struct drvmgr_dev *dev;
-
- DBG("OCCAN: Opening %d\n\r",minor);
-
- /* get can device */
- if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
- DBG("Wrong minor %d\n", minor);
- return RTEMS_UNSATISFIED; /* NODEV */
- }
- can = (occan_priv *)dev->priv;
-
- /* already opened? */
- rtems_semaphore_obtain(can->devsem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- if ( can->open ){
- rtems_semaphore_release(can->devsem);
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- }
- can->open = 1;
- rtems_semaphore_release(can->devsem);
-
- SPIN_INIT(&can->devlock, can->devName);
-
- /* allocate fifos */
- can->rxfifo = occan_fifo_create(DEFAULT_RX_FIFO_LEN);
- if ( !can->rxfifo ){
- can->open = 0;
- return RTEMS_NO_MEMORY; /* ENOMEM */
- }
-
- can->txfifo = occan_fifo_create(DEFAULT_TX_FIFO_LEN);
- if ( !can->txfifo ){
- occan_fifo_free(can->rxfifo);
- can->rxfifo= NULL;
- can->open = 0;
- return RTEMS_NO_MEMORY; /* ENOMEM */
- }
-
- DBG("OCCAN: Opening %d success\n\r",minor);
-
- can->started = 0;
- can->channel = 0; /* Default to first can link */
- can->txblk = 1; /* Default to Blocking mode */
- can->rxblk = 1; /* Default to Blocking mode */
- can->single_mode = 1; /* single mode acceptance filter */
-
- /* reset stat counters */
- memset(&can->stats,0,sizeof(occan_stats));
-
- /* HW must be in reset mode here (close and initializes resets core...)
- *
- * 1. set default modes/speeds
- */
- pelican_open(can);
-
- return RTEMS_SUCCESSFUL;
-}
-
-static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
-{
- occan_priv *can;
- struct drvmgr_dev *dev;
-
- DBG("OCCAN: Closing %d\n\r",minor);
-
- if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
- return RTEMS_INVALID_NAME;
- }
- can = (occan_priv *)dev->priv;
-
- /* stop if running */
- if ( can->started )
- pelican_stop(can);
-
- /* Enter Reset Mode */
- WRITE_REG(can, &can->regs->mode, PELICAN_MOD_RESET);
-
- /* free fifo memory */
- occan_fifo_free(can->rxfifo);
- occan_fifo_free(can->txfifo);
-
- can->rxfifo = NULL;
- can->txfifo = NULL;
-
- can->open = 0;
-
- return RTEMS_SUCCESSFUL;
-}
-
-static rtems_device_driver occan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
-{
- occan_priv *can;
- struct drvmgr_dev *dev;
- rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
- CANMsg *dstmsg, *srcmsg;
- SPIN_IRQFLAGS(oldLevel);
- int left;
-
- if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
- return RTEMS_INVALID_NAME;
- }
- can = (occan_priv *)dev->priv;
-
- if ( !can->started ){
- DBG("OCCAN: cannot read from minor %d when not started\n\r",minor);
- return RTEMS_RESOURCE_IN_USE; /* -EBUSY*/
- }
-
- /* does at least one message fit */
- left = rw_args->count;
- if ( left < sizeof(CANMsg) ){
- DBG("OCCAN: minor %d length of buffer must be at least %d, our is %d\n\r",minor,sizeof(CANMsg),left);
- return RTEMS_INVALID_NAME; /* -EINVAL */
- }
-
- /* get pointer to start where to put CAN messages */
- dstmsg = (CANMsg *)rw_args->buffer;
- if ( !dstmsg ){
- DBG("OCCAN: minor %d read: input buffer is NULL\n\r",minor);
- return RTEMS_INVALID_NAME; /* -EINVAL */
- }
-
- while (left >= sizeof(CANMsg) ){
-
- /* turn off interrupts */
- SPIN_LOCK_IRQ(&can->devlock, oldLevel);
-
- /* A bus off interrupt may have occured after checking can->started */
- if ( can->status & (OCCAN_STATUS_ERR_BUSOFF|OCCAN_STATUS_RESET) ){
- SPIN_UNLOCK_IRQ(&can->devlock, oldLevel);
- DBG("OCCAN: read is cancelled due to a BUS OFF error\n\r");
- rw_args->bytes_moved = rw_args->count-left;
- return RTEMS_IO_ERROR; /* EIO */
- }
-
- srcmsg = occan_fifo_claim_get(can->rxfifo);
- if ( !srcmsg ){
- /* no more messages in reception fifo.
- * Wait for incoming packets only if in
- * blocking mode AND no messages been
- * read before.
- */
- if ( !can->rxblk || (left != rw_args->count) ){
- /* turn on interrupts again */
- SPIN_UNLOCK_IRQ(&can->devlock, oldLevel);
- break;
- }
-
- /* turn on interrupts again */
- SPIN_UNLOCK_IRQ(&can->devlock, oldLevel);
-
- DBG("OCCAN: Waiting for RX int\n\r");
-
- /* wait for incoming messages */
- rtems_semaphore_obtain(can->rxsem, RTEMS_WAIT,
- RTEMS_NO_TIMEOUT);
-
- /* did we get woken up by a BUS OFF error? */
- if ( can->status & (OCCAN_STATUS_ERR_BUSOFF|OCCAN_STATUS_RESET) ){
- DBG("OCCAN: Blocking read got woken up by BUS OFF error\n\r");
- /* At this point it should not matter how many messages we handled */
- rw_args->bytes_moved = rw_args->count-left;
- return RTEMS_IO_ERROR; /* EIO */
- }
-
- /* no errors detected, it must be a message */
- continue;
- }
-
- /* got message, copy it to userspace buffer */
- *dstmsg = *srcmsg;
-
- /* Return borrowed message, RX interrupt can use it again */
- occan_fifo_get(can->rxfifo);
-
- /* turn on interrupts again */
- SPIN_UNLOCK_IRQ(&can->devlock, oldLevel);
-
- /* increase pointers */
- left -= sizeof(CANMsg);
- dstmsg++;
- }
-
- /* save number of read bytes. */
- rw_args->bytes_moved = rw_args->count-left;
- if ( rw_args->bytes_moved == 0 ){
- DBG("OCCAN: minor %d read would block, returning\n\r",minor);
- return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
- }
- return RTEMS_SUCCESSFUL;
-}
-
-static rtems_device_driver occan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
-{
- occan_priv *can;
- struct drvmgr_dev *dev;
- rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
- CANMsg *msg,*fifo_msg;
- SPIN_IRQFLAGS(oldLevel);
- int left;
-
- DBG("OCCAN: Writing %d bytes from 0x%lx (%d)\n\r",rw_args->count,rw_args->buffer,sizeof(CANMsg));
-
- if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
- return RTEMS_INVALID_NAME;
- }
- can = (occan_priv *)dev->priv;
-
- if ( !can->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- left = rw_args->count;
- if ( (left < sizeof(CANMsg)) || (!rw_args->buffer) ){
- return RTEMS_INVALID_NAME; /* EINVAL */
- }
-
- msg = (CANMsg *)rw_args->buffer;
-
- /* limit CAN message length to 8 */
- msg->len = (msg->len > 8) ? 8 : msg->len;
-
-#ifdef DEBUG_VERBOSE
- pelican_regs_print(can->regs);
- occan_stat_print(&can->stats);
-#endif
-
- /* turn off interrupts */
- SPIN_LOCK_IRQ(&can->devlock, oldLevel);
-
- /* A bus off interrupt may have occured after checking can->started */
- if ( can->status & (OCCAN_STATUS_ERR_BUSOFF|OCCAN_STATUS_RESET) ){
- SPIN_UNLOCK_IRQ(&can->devlock, oldLevel);
- rw_args->bytes_moved = 0;
- return RTEMS_IO_ERROR; /* EIO */
- }
-
- /* If no messages in software tx fifo, we will
- * try to send first message by putting it directly
- * into the HW TX fifo.
- */
- if ( occan_fifo_empty(can->txfifo) ){
- /*pelican_regs_print(cans[minor+1].regs);*/
- if ( !pelican_send(can,msg) ) {
- /* First message put directly into HW TX fifo
- * This will turn TX interrupt on.
- */
- left -= sizeof(CANMsg);
- msg++;
-
-#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
- /* Mark that we have put at least one msg in TX FIFO */
- can->sending = 1;
-#endif
-
- /* bump stat counters */
- can->stats.tx_msgs++;
-
- DBG("OCCAN: Sending direct via HW\n\r");
- }
- }
-
- /* Put messages into software fifo */
- while ( left >= sizeof(CANMsg) ){
-
- /* limit CAN message length to 8 */
- msg->len = (msg->len > 8) ? 8 : msg->len;
-
- fifo_msg = occan_fifo_put_claim(can->txfifo,0);
- if ( !fifo_msg ){
-
- DBG("OCCAN: FIFO is full\n\r");
- /* Block only if no messages previously sent
- * and no in blocking mode
- */
- if ( !can->txblk || (left != rw_args->count) )
- break;
-
- /* turn on interupts again and wait
- INT_ON
- WAIT FOR FREE BUF;
- INT_OFF;
- CHECK_IF_FIFO_EMPTY ==> SEND DIRECT VIA HW;
- */
- SPIN_UNLOCK_IRQ(&can->devlock, oldLevel);
-
- DBG("OCCAN: Waiting for tx int\n\r");
-
- rtems_semaphore_obtain(can->txsem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
-
- /* did we get woken up by a BUS OFF error? */
- if ( can->status & (OCCAN_STATUS_ERR_BUSOFF|OCCAN_STATUS_RESET) ){
- DBG("OCCAN: Blocking write got woken up by BUS OFF error or RESET event\n\r");
- /* At this point it should not matter how many messages we handled */
- rw_args->bytes_moved = rw_args->count-left;
- return RTEMS_IO_ERROR; /* EIO */
- }
-
- SPIN_LOCK_IRQ(&can->devlock, oldLevel);
-
- if ( occan_fifo_empty(can->txfifo) ){
- if ( !pelican_send(can,msg) ) {
- /* First message put directly into HW TX fifo
- * This will turn TX interrupt on.
- */
- left -= sizeof(CANMsg);
- msg++;
-
-#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
- /* Mark that we have put at least one msg in TX FIFO */
- can->sending = 1;
-#endif
-
- /* bump stat counters */
- can->stats.tx_msgs++;
-
- DBG("OCCAN: Sending direct2 via HW\n\r");
- }
- }
- continue;
- }
-
- /* copy message into fifo area */
- *fifo_msg = *msg;
-
- /* tell interrupt handler about the message */
- occan_fifo_put(can->txfifo);
-
- DBG("OCCAN: Put info fifo SW\n\r");
-
- /* Prepare insert of next message */
- msg++;
- left-=sizeof(CANMsg);
- }
-
- SPIN_UNLOCK_IRQ(&can->devlock, oldLevel);
-
- rw_args->bytes_moved = rw_args->count-left;
- DBG("OCCAN: Sent %d\n\r",rw_args->bytes_moved);
-
- if ( left == rw_args->count )
- return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
- return RTEMS_SUCCESSFUL;
-}
-
-static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
-{
- int ret;
- occan_speed_regs timing;
- occan_priv *can;
- struct drvmgr_dev *dev;
- unsigned int speed;
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
- struct occan_afilter *afilter;
- occan_stats *dststats;
- unsigned int rxcnt,txcnt;
-
- DBG("OCCAN: IOCTL %d\n\r",ioarg->command);
-
- if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
- return RTEMS_INVALID_NAME;
- }
- can = (occan_priv *)dev->priv;
-
- ioarg->ioctl_return = 0;
- switch(ioarg->command){
- case OCCAN_IOC_SET_SPEED:
-
- /* cannot change speed during run mode */
- if ( can->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- /* get speed rate from argument */
- speed = (unsigned int)ioarg->buffer;
- ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing);
- if ( ret )
- return RTEMS_INVALID_NAME; /* EINVAL */
-
- /* set the speed regs of the CAN core */
- /* occan_set_speedregs(can,timing); */
-
- /* save timing/speed */
- can->speed = speed;
- can->timing = timing;
- break;
-
- case OCCAN_IOC_SET_BTRS:
- /* Set BTR registers manually
- * Read OCCAN Manual.
- */
- if ( can->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- can->speed = 0; /* custom */
- can->timing.btr1 = (unsigned int)ioarg->buffer & 0xff;
- can->timing.btr0 = ((unsigned int)ioarg->buffer>>8) & 0xff;
-/*
- can->timing.sjw = (btr0 >> OCCAN_BUSTIM_SJW_BIT) & 0x3;
- can->timing.brp = btr0 & OCCAN_BUSTIM_BRP;
- can->timing.tseg1 = btr1 & 0xf;
- can->timing.tseg2 = (btr1 >> OCCAN_BUSTIM_TSEG2_BIT) & 0x7;
- can->timing.sam = (btr1 >> 7) & 0x1;
- */
- break;
-
- case OCCAN_IOC_SPEED_AUTO:
- return RTEMS_NOT_IMPLEMENTED;
-
- case OCCAN_IOC_SET_BUFLEN:
- /* set rx & tx fifo buffer length */
- if ( can->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- rxcnt = (unsigned int)ioarg->buffer & 0x0000ffff;
- txcnt = (unsigned int)ioarg->buffer >> 16;
-
- occan_fifo_free(can->rxfifo);
- occan_fifo_free(can->txfifo);
-
- /* allocate new buffers */
- can->rxfifo = occan_fifo_create(rxcnt);
- can->txfifo = occan_fifo_create(txcnt);
-
- if ( !can->rxfifo || !can->txfifo )
- return RTEMS_NO_MEMORY; /* ENOMEM */
- break;
-
- case OCCAN_IOC_GET_CONF:
- return RTEMS_NOT_IMPLEMENTED;
- break;
-
- case OCCAN_IOC_GET_STATS:
- dststats = (occan_stats *)ioarg->buffer;
- if ( !dststats )
- return RTEMS_INVALID_NAME; /* EINVAL */
-
- /* copy data stats into userspace buffer */
- if ( can->rxfifo )
- can->stats.rx_sw_dovr = can->rxfifo->ovcnt;
- *dststats = can->stats;
- break;
-
- case OCCAN_IOC_GET_STATUS:
- /* return the status of the */
- if ( !ioarg->buffer )
- return RTEMS_INVALID_NAME;
-
- *(unsigned int *)ioarg->buffer = can->status;
- break;
-
- /* Set physical link */
- case OCCAN_IOC_SET_LINK:
-#ifdef REDUNDANT_CHANNELS
- if ( can->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- /* switch HW channel */
- can->channel = (unsigned int)ioargs->buffer;
-#else
- return RTEMS_NOT_IMPLEMENTED;
-#endif
- break;
-
- case OCCAN_IOC_SET_FILTER:
- if ( can->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- afilter = (struct occan_afilter *)ioarg->buffer;
-
- if ( !afilter )
- return RTEMS_INVALID_NAME; /* EINVAL */
-
- /* copy acceptance filter */
- can->acode[0] = afilter->code[0];
- can->acode[1] = afilter->code[1];
- can->acode[2] = afilter->code[2];
- can->acode[3] = afilter->code[3];
-
- can->amask[0] = afilter->mask[0];
- can->amask[1] = afilter->mask[1];
- can->amask[2] = afilter->mask[2];
- can->amask[3] = afilter->mask[3];
-
- can->single_mode = ( afilter->single_mode ) ? 1 : 0;
-
- /* Acceptance filter is written to hardware
- * when starting.
- */
- /* pelican_set_accept(can,can->acode,can->amask);*/
- break;
-
- case OCCAN_IOC_SET_BLK_MODE:
- can->rxblk = (unsigned int)ioarg->buffer & OCCAN_BLK_MODE_RX;
- can->txblk = ((unsigned int)ioarg->buffer & OCCAN_BLK_MODE_TX) >> 1;
- break;
-
- case OCCAN_IOC_START:
- if ( can->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- if ( pelican_start(can) )
- return RTEMS_NO_MEMORY; /* failed because of no memory, can happen if SET_BUFLEN failed */
- /* can->started = 1; -- Is set in pelican_start due to interrupt may occur before we
- * get here.
- */
- break;
-
- case OCCAN_IOC_STOP:
- if ( !can->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- pelican_stop(can);
- can->started = 0;
- break;
-
- default:
- return RTEMS_NOT_DEFINED;
- }
- return RTEMS_SUCCESSFUL;
-}
-
-void occan_interrupt(void *arg)
-{
- occan_priv *can = arg;
- unsigned char iflags;
- pelican_regs *regs = can->regs;
- CANMsg *msg;
- int signal_rx=0, signal_tx=0;
- unsigned char tmp, errcode, arbcode;
- int tx_error_cnt,rx_error_cnt;
- SPIN_ISR_IRQFLAGS(irqflags);
-
- if ( !can->started )
- return; /* Spurious Interrupt, do nothing */
-
- SPIN_LOCK(&can->devlock, irqflags);
- while (1) {
-
- iflags = READ_REG(can, &can->regs->intflags);
-
-#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
- /* TX IRQ may be cleared when reading regs->intflags due
- * to a bug in some chips. Instead of looking at the TX_IRQ_FLAG
- * the TX-fifo emoty register is looked at when something has
- * been scheduled for transmission.
- */
- if ((iflags & PELICAN_IF_TX) == 0) {
- if (can->sending && pelican_tx_ready(can)) {
- can->sending = 0;
- iflags |= PELICAN_IF_TX;
- }
- }
-#endif
-
- if (iflags == 0)
- break;
- /* still interrupts to handle */
-
- can->stats.ints++;
-
- if ( iflags & PELICAN_IF_RX ){
- /* the rx fifo is not empty
- * put 1 message into rxfifo for later use
- */
-
- /* get empty (or make room) message */
- msg = occan_fifo_put_claim(can->rxfifo,1);
- tmp = READ_REG(can, &regs->rx_fi_xff);
- msg->extended = tmp >> 7;
- msg->rtr = (tmp >> 6) & 1;
- msg->len = tmp = tmp & 0x0f;
-
- if ( msg->extended ){
- /* extended message */
- msg->id = READ_REG(can, &regs->msg.rx_eff.id[0])<<(5+8+8) |
- READ_REG(can, &regs->msg.rx_eff.id[1])<<(5+8) |
- READ_REG(can, &regs->msg.rx_eff.id[2])<<5 |
- READ_REG(can, &regs->msg.rx_eff.id[3])>>3;
-
- while(tmp--){
- msg->data[tmp] = READ_REG(can, &regs->msg.rx_eff.data[tmp]);
- }
- /*
- msg->data[0] = READ_REG(can, &regs->msg.rx_eff.data[0]);
- msg->data[1] = READ_REG(can, &regs->msg.rx_eff.data[1]);
- msg->data[2] = READ_REG(can, &regs->msg.rx_eff.data[2]);
- msg->data[3] = READ_REG(can, &regs->msg.rx_eff.data[3]);
- msg->data[4] = READ_REG(can, &regs->msg.rx_eff.data[4]);
- msg->data[5] = READ_REG(can, &regs->msg.rx_eff.data[5]);
- msg->data[6] = READ_REG(can, &regs->msg.rx_eff.data[6]);
- msg->data[7] = READ_REG(can, &regs->msg.rx_eff.data[7]);
- */
- }else{
- /* standard message */
- msg->id = READ_REG(can, &regs->msg.rx_sff.id[0])<<3 |
- READ_REG(can, &regs->msg.rx_sff.id[1])>>5;
-
- while(tmp--){
- msg->data[tmp] = READ_REG(can, &regs->msg.rx_sff.data[tmp]);
- }
- /*
- msg->data[0] = READ_REG(can, &regs->msg.rx_sff.data[0]);
- msg->data[1] = READ_REG(can, &regs->msg.rx_sff.data[1]);
- msg->data[2] = READ_REG(can, &regs->msg.rx_sff.data[2]);
- msg->data[3] = READ_REG(can, &regs->msg.rx_sff.data[3]);
- msg->data[4] = READ_REG(can, &regs->msg.rx_sff.data[4]);
- msg->data[5] = READ_REG(can, &regs->msg.rx_sff.data[5]);
- msg->data[6] = READ_REG(can, &regs->msg.rx_sff.data[6]);
- msg->data[7] = READ_REG(can, &regs->msg.rx_sff.data[7]);
- */
- }
-
- /* Re-Enable RX buffer for a new message */
- WRITE_REG(can, &regs->cmd, PELICAN_CMD_RELRXBUF);
-
- /* make message available to the user */
- occan_fifo_put(can->rxfifo);
-
- /* bump stat counters */
- can->stats.rx_msgs++;
-
- /* signal the semaphore only once */
- signal_rx = 1;
- }
-
- if ( iflags & PELICAN_IF_TX ) {
-
- /* there is room in tx fifo of HW */
-
- if ( !occan_fifo_empty(can->txfifo) ){
- /* send 1 more messages */
- msg = occan_fifo_claim_get(can->txfifo);
-
- if ( pelican_send(can,msg) ){
- /* ERROR! We got an TX interrupt telling us
- * tx fifo is empty, yet it is not.
- *
- * Complain about this max 10 times
- */
- if ( can->stats.tx_buf_error < 10 ){
- printk("OCCAN: got TX interrupt but TX fifo in not empty (%d)\n\r",can->stats.tx_buf_error);
- }
- can->status |= OCCAN_STATUS_QUEUE_ERROR;
- can->stats.tx_buf_error++;
- }
-#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
- can->sending = 1;
-#endif
-
- /* free software-fifo space taken by sent message */
- occan_fifo_get(can->txfifo);
-
- /* bump stat counters */
- can->stats.tx_msgs++;
-
- /* wake any sleeping thread waiting for "fifo not full" */
- signal_tx = 1;
- }
- }
-
- if ( iflags & PELICAN_IF_ERRW ){
- tx_error_cnt = READ_REG(can, &regs->tx_err_cnt);
- rx_error_cnt = READ_REG(can, &regs->rx_err_cnt);
-
- /* 1. if bus off tx error counter = 127 */
- if ( (tx_error_cnt > 96) || (rx_error_cnt > 96) ){
- /* in Error Active Warning area or BUS OFF */
- can->status |= OCCAN_STATUS_WARN;
-
- /* check reset bit for reset mode */
- if ( READ_REG(can, &regs->mode) & PELICAN_MOD_RESET ){
- /* in reset mode ==> bus off */
- can->status |= OCCAN_STATUS_ERR_BUSOFF | OCCAN_STATUS_RESET;
-
- /***** pelican_stop(can) ******
- * turn off interrupts
- * enter reset mode (HW already done that for us)
- */
- WRITE_REG(can, &regs->inten,0);
-
- /* Indicate that we are not started any more.
- * This will make write/read return with EBUSY
- * on read/write attempts.
- *
- * User must issue a ioctl(START) to get going again.
- */
- can->started = 0;
-
- /* signal any waiting read/write threads, so that they
- * can handle the bus error.
- */
- signal_rx = 1;
- signal_tx = 1;
-
- /* ingnore any old pending interrupt */
- break;
- }
-
- }else{
- /* not in Upper Error Active area any more */
- can->status &= ~(OCCAN_STATUS_WARN);
- }
- can->stats.err_warn++;
- }
-
- if ( iflags & PELICAN_IF_DOVR){
- can->status |= OCCAN_STATUS_OVERRUN;
- can->stats.err_dovr++;
- DBG("OCCAN_INT: DOVR\n\r");
- }
-
- if ( iflags & PELICAN_IF_ERRP){
- /* Let the error counters decide what kind of
- * interrupt it was. In/Out of EPassive area.
- */
- tx_error_cnt = READ_REG(can, &regs->tx_err_cnt);
- rx_error_cnt = READ_REG(can, &regs->rx_err_cnt);
-
- if ( (tx_error_cnt > 127) || (rx_error_cnt > 127) ){
- can->status |= OCCAN_STATUS_ERR_PASSIVE;
- }else{
- can->status &= ~(OCCAN_STATUS_ERR_PASSIVE);
- }
-
- /* increase Error Passive In/out interrupt counter */
- can->stats.err_errp++;
- }
-
- if ( iflags & PELICAN_IF_ARB){
- arbcode = READ_REG(can, &regs->arbcode);
- can->stats.err_arb_bitnum[arbcode & PELICAN_ARB_BITS]++;
- can->stats.err_arb++;
- DBG("OCCAN_INT: ARB (0x%x)\n\r",arbcode & PELICAN_ARB_BITS);
- }
-
- if ( iflags & PELICAN_IF_BUS){
- /* Some kind of BUS error, only used for
- * statistics. Error Register is decoded
- * and put into can->stats.
- */
- errcode = READ_REG(can, &regs->errcode);
- switch( errcode & PELICAN_ECC_CODE ){
- case PELICAN_ECC_CODE_BIT:
- can->stats.err_bus_bit++;
- break;
- case PELICAN_ECC_CODE_FORM:
- can->stats.err_bus_form++;
- break;
- case PELICAN_ECC_CODE_STUFF:
- can->stats.err_bus_stuff++;
- break;
- case PELICAN_ECC_CODE_OTHER:
- can->stats.err_bus_other++;
- break;
- }
-
- /* Get Direction (TX/RX) */
- if ( errcode & PELICAN_ECC_DIR ){
- can->stats.err_bus_rx++;
- }else{
- can->stats.err_bus_tx++;
- }
-
- /* Get Segment in frame that went wrong */
- can->stats.err_bus_segs[errcode & PELICAN_ECC_SEG]++;
-
- /* total number of bus errors */
- can->stats.err_bus++;
- }
- }
- SPIN_UNLOCK(&can->devlock, irqflags);
-
- /* signal Binary semaphore, messages available! */
- if ( signal_rx ){
- rtems_semaphore_release(can->rxsem);
- }
-
- if ( signal_tx ){
- rtems_semaphore_release(can->txsem);
- }
-}
-
-/*******************************************************************************
- * FIFO IMPLEMENTATION
- */
-
-static occan_fifo *occan_fifo_create(int cnt)
-{
- occan_fifo *fifo;
- fifo = malloc(sizeof(occan_fifo)+cnt*sizeof(CANMsg));
- if ( fifo ){
- fifo->cnt = cnt;
- fifo->full = 0;
- fifo->ovcnt = 0;
- fifo->base = (CANMsg *)&fifo->fifoarea[0];
- fifo->tail = fifo->head = fifo->base;
- /* clear CAN Messages */
- memset(fifo->base,0,cnt * sizeof(CANMsg));
- }
- return fifo;
-}
-
-static void occan_fifo_free(occan_fifo *fifo)
-{
- if ( fifo )
- free(fifo);
-}
-
-static int occan_fifo_full(occan_fifo *fifo)
-{
- return fifo->full;
-}
-
-static int occan_fifo_empty(occan_fifo *fifo)
-{
- return (!fifo->full) && (fifo->head == fifo->tail);
-}
-
-/* Stage 1 - get buffer to fill (never fails if force!=0) */
-static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force)
-{
- if ( !fifo )
- return NULL;
-
- if ( occan_fifo_full(fifo) ){
-
- if ( !force )
- return NULL;
-
- /* all buffers already used ==> overwrite the oldest */
- fifo->ovcnt++;
- occan_fifo_get(fifo);
- }
-
- return fifo->head;
-}
-
-/* Stage 2 - increment indexes */
-static void occan_fifo_put(occan_fifo *fifo)
-{
- if ( occan_fifo_full(fifo) )
- return;
-
- /* wrap around */
- fifo->head = (fifo->head >= &fifo->base[fifo->cnt-1])? fifo->base : fifo->head+1;
-
- if ( fifo->head == fifo->tail )
- fifo->full = 1;
-}
-
-static CANMsg *occan_fifo_claim_get(occan_fifo *fifo)
-{
- if ( occan_fifo_empty(fifo) )
- return NULL;
-
- /* return oldest message */
- return fifo->tail;
-}
-
-
-static void occan_fifo_get(occan_fifo *fifo)
-{
- if ( !fifo )
- return;
-
- if ( occan_fifo_empty(fifo) )
- return;
-
- /* increment indexes */
- fifo->tail = (fifo->tail >= &fifo->base[fifo->cnt-1]) ?
- fifo->base : fifo->tail+1;
- fifo->full = 0;
-}
-
-static void occan_fifo_clr(occan_fifo *fifo)
-{
- fifo->full = 0;
- fifo->ovcnt = 0;
- fifo->head = fifo->tail = fifo->base;
-}
-
-/******************************************************************************/