diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2011-12-20 16:27:54 +0100 |
---|---|---|
committer | Daniel Hellstrom <daniel@gaisler.com> | 2015-04-17 01:10:17 +0200 |
commit | 3681925508c0da88fee6325ea35ead7b112856c6 (patch) | |
tree | 0886351bec0218ed4689c68e5442b75341cbc169 /c/src/lib/libbsp/sparc/shared/can | |
parent | LEON: updated and added PCI peripherals for LEON BSPs (diff) | |
download | rtems-3681925508c0da88fee6325ea35ead7b112856c6.tar.bz2 |
LEON: updated shared drivers to Driver Manger framework
Some bugfixes at the same time. After this patch the drivers
may be used on RASTA systems having a big-endian PCI layout.
Removed not up to date changelogs, rely on git log instead.
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/can')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/can/grcan.c | 1747 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/can/occan.c | 1181 |
2 files changed, 1525 insertions, 1403 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/can/grcan.c b/c/src/lib/libbsp/sparc/shared/can/grcan.c index 7833f8c1d6..7ad53e1fb6 100644 --- a/c/src/lib/libbsp/sparc/shared/can/grcan.c +++ b/c/src/lib/libbsp/sparc/shared/can/grcan.c @@ -1,19 +1,12 @@ /* * GRCAN driver - */ - -/* + * * COPYRIGHT (c) 2007. - * Gaisler Research. + * 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. - * - * - * 2007-06-13, Daniel Hellstrom <daniel@gaisler.com> - * New driver in sparc shared directory. Parts taken - * from rasta grhcan driver. */ #include <bsp.h> @@ -26,22 +19,26 @@ #include <rtems/bspIo.h> #include <grcan.h> +#include <drvmgr/drvmgr.h> +#include <drvmgr/ambapp_bus.h> #include <ambapp.h> -#include <grlib.h> #define WRAP_AROUND_TX_MSGS 1 #define WRAP_AROUND_RX_MSGS 2 #define GRCAN_MSG_SIZE sizeof(struct grcan_msg) #define BLOCK_SIZE (16*4) +/* grcan needs to have it buffers aligned to 1k boundaries */ +#define BUFFER_ALIGNMENT_NEEDS 1024 + /* Default Maximium buffer size for statically allocated buffers */ #ifndef TX_BUF_SIZE -#define TX_BUF_SIZE (BLOCK_SIZE*16) + #define TX_BUF_SIZE (BLOCK_SIZE*16) #endif /* Make receiver buffers bigger than transmitt */ #ifndef RX_BUF_SIZE -#define RX_BUF_SIZE ((3*BLOCK_SIZE)*16) + #define RX_BUF_SIZE ((3*BLOCK_SIZE)*16) #endif #ifndef IRQ_GLOBAL_PREPARE @@ -68,35 +65,13 @@ #define IRQ_MASK(irqno) #endif -#ifndef GRCAN_PREFIX - #define GRCAN_PREFIX(name) grcan##name -#endif - -#ifndef MEMAREA_TO_HW - #define MEMAREA_TO_HW(x) (x) -#endif - -/* default name to /dev/grcan0 */ -#if !defined(GRCAN_DEVNAME) || !defined(GRCAN_DEVNAME_NO) - #undef GRCAN_DEVNAME - #undef GRCAN_DEVNAME_NO - #define GRCAN_DEVNAME "/dev/grcan0" - #define GRCAN_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no)) -#endif - -#ifndef GRCAN_REG_INT - #define GRCAN_REG_INT(handler,irqno,arg) set_vector(handler,irqno+0x10,1) - #undef GRCAN_DEFINE_INTHANDLER - #define GRCAN_DEFINE_INTHANDLER -#endif - #ifndef GRCAN_DEFAULT_BAUD - /* default to 500kbits/s */ - #define GRCAN_DEFAULT_BAUD 500000 + /* default to 500kbits/s */ + #define GRCAN_DEFAULT_BAUD 500000 #endif #ifndef GRCAN_SAMPLING_POINT -#define GRCAN_SAMPLING_POINT 80 + #define GRCAN_SAMPLING_POINT 80 #endif /* Uncomment for debug output */ @@ -114,63 +89,9 @@ /*********************************************************/ -/* grcan needs to have it buffers aligned to 1k boundaries */ -#define BUFFER_ALIGNMENT_NEEDS 1024 - -#ifdef STATICALLY_ALLOCATED_TX_BUFFER -static unsigned int tx_circbuf[GRCAN_MAX_CORES][TX_BUF_SIZE] - __attribute__ ((aligned(BUFFER_ALIGNMENT_NEEDS))); -#define STATIC_TX_BUF_SIZE TX_BUF_SIZE -#define STATIC_TX_BUF_ADDR(core) (&tx_circbuf[(core)][0]) -#endif - -#ifdef STATICALLY_ALLOCATED_RX_BUFFER -static unsigned int rx_circbuf[GRCAN_MAX_CORES][RX_BUF_SIZE] - __attribute__ ((aligned(BUFFER_ALIGNMENT_NEEDS))); -#define STATIC_RX_BUF_SIZE RX_BUF_SIZE -#define STATIC_RX_BUF_ADDR(core) (&rx_circbuf[(core)][0]) -#endif - -/* - * If USE_AT697_RAM is defined the RAM on the AT697 board will be used for DMA buffers (but rx message queue is always in AT697 ram). - * USE_AT697_DMA specifies whether the messages will be fetched using DMA or PIO. - * - * RASTA_PCI_BASE is the base address of the GRPCI AHB slave - * - * GRCAN_BUF_SIZE must be set to the size (in bytes) of the GRCAN DMA buffers. - * - * RX_QUEUE_SIZE defines the number of messages that fits in the RX message queue. On RX interrupts the messages in the DMA buffer - * are copied into the message queue (using dma if the rx buf is not in the AT697 ram). - */ - -/*#define USE_AT697_RAM 1 */ -#define USE_AT697_DMA 1 -#define RASTA_PCI_BASE 0xe0000000 -#define GRCAN_BUF_SIZE 4096 -#define RX_QUEUE_SIZE 1024 - -#define INDEX(x) ( x&(RX_QUEUE_SIZE-1) ) - -/* pa(x) - * - * x: address in AT697 address space - * - * returns the address in the RASTA address space that can be used to access x with dma. - * -*/ -#ifdef USE_AT697_RAM -static inline unsigned int pa(unsigned int addr) { - return ((addr & 0x0fffffff) | RASTA_PCI_BASE); -} -#else -static inline unsigned int pa(unsigned int addr) { - return ((addr & 0x0fffffff) | 0x40000000); -} -#endif - struct grcan_msg { - unsigned int head[2]; - unsigned char data[8]; + unsigned int head[2]; + unsigned char data[8]; }; struct grcan_config { @@ -181,43 +102,41 @@ struct grcan_config { }; struct grcan_priv { - unsigned int baseaddr, ram_base; - struct grcan_regs *regs; - int irq; - int minor; - int open; - int started; - unsigned int channel; - int flushing; - unsigned int corefreq_hz; - - /* Circular DMA buffers */ - void *_rx; - void *_tx; - struct grcan_msg *rx; - struct grcan_msg *tx; - unsigned int rxbuf_size; /* requested RX buf size in bytes */ - unsigned int txbuf_size; /* requested TX buf size in bytes */ - - int txblock, rxblock; - int txcomplete, rxcomplete; - int txerror, rxerror; - - struct grcan_filter sfilter; - struct grcan_filter afilter; - int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */ - struct grcan_config config; - struct grcan_stats stats; - - rtems_id rx_sem, tx_sem, txempty_sem, dev_sem; + struct drvmgr_dev *dev; /* Driver manager device */ + char devName[32]; /* Device Name */ + unsigned int baseaddr, ram_base; + struct grcan_regs *regs; + int irq; + int minor; + int open; + int started; + unsigned int channel; + int flushing; + unsigned int corefreq_hz; + + /* Circular DMA buffers */ + void *_rx, *_rx_hw; + void *_tx, *_tx_hw; + void *txbuf_adr; + void *rxbuf_adr; + struct grcan_msg *rx; + struct grcan_msg *tx; + unsigned int rxbuf_size; /* requested RX buf size in bytes */ + unsigned int txbuf_size; /* requested TX buf size in bytes */ + + int txblock, rxblock; + int txcomplete, rxcomplete; + int txerror, rxerror; + + struct grcan_filter sfilter; + struct grcan_filter afilter; + int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */ + struct grcan_config config; + struct grcan_stats stats; + + rtems_id rx_sem, tx_sem, txempty_sem, dev_sem; }; -static int grcan_core_cnt; -struct grcan_priv *grcans; -static struct ambapp_bus *amba_bus; -struct grcan_device_info *grcan_cores; -static int grcan_core_cnt; - static rtems_device_driver grcan_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); @@ -227,6 +146,8 @@ static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_de #define GRCAN_DRIVER_TABLE_ENTRY { grcan_initialize, grcan_open, grcan_close, grcan_read, grcan_write, grcan_ioctl } +static void __inline__ grcan_hw_reset(struct grcan_regs *regs); + static unsigned int grcan_hw_read_try( struct grcan_priv *pDev, struct grcan_regs *regs, @@ -251,11 +172,7 @@ static void grcan_hw_sync( struct grcan_regs *regs, struct grcan_filter *sfilter); -#ifndef GRCAN_DONT_DECLARE_IRQ_HANDLER -static rtems_isr grcan_interrupt_handler(rtems_vector_number v); -#endif - -static void grcan_interrupt(struct grcan_priv *pDev); +static void grcan_interrupt(void *arg); #ifdef GRCAN_REG_BYPASS_CACHE #define READ_REG(address) _grcan_read_nocache((unsigned int)(address)) @@ -268,12 +185,12 @@ static void grcan_interrupt(struct grcan_priv *pDev); #define READ_DMA_BYTE(address) _grcan_read_nocache_byte((unsigned int)(address)) static unsigned char __inline__ _grcan_read_nocache_byte(unsigned int address) { - unsigned char tmp; - __asm__ (" lduba [%1]1, %0 " - : "=r"(tmp) - : "r"(address) - ); - return tmp; + unsigned char tmp; + __asm__ (" lduba [%1]1, %0 " + : "=r"(tmp) + : "r"(address) + ); + return tmp; } #else #define READ_DMA_WORD(address) (*(volatile unsigned int *)(address)) @@ -283,17 +200,228 @@ static unsigned char __inline__ _grcan_read_nocache_byte(unsigned int address) #if defined(GRCAN_REG_BYPASS_CACHE) || defined(GRCAN_DMA_BYPASS_CACHE) static unsigned int __inline__ _grcan_read_nocache(unsigned int address) { - unsigned int tmp; - __asm__ (" lda [%1]1, %0 " - : "=r"(tmp) - : "r"(address) - ); - return tmp; + unsigned int tmp; + __asm__ (" lda [%1]1, %0 " + : "=r"(tmp) + : "r"(address) + ); + return tmp; } #endif static rtems_driver_address_table grcan_driver = GRCAN_DRIVER_TABLE_ENTRY; +static int grcan_driver_io_registered = 0; +static rtems_device_major_number grcan_driver_io_major = 0; + +/******************* Driver manager interface ***********************/ + +/* Driver prototypes */ +int grcan_register_io(rtems_device_major_number *m); +int grcan_device_init(struct grcan_priv *pDev); + +int grcan_init2(struct drvmgr_dev *dev); +int grcan_init3(struct drvmgr_dev *dev); + +struct drvmgr_drv_ops grcan_ops = +{ + .init = {NULL, grcan_init2, grcan_init3, NULL}, + .remove = NULL, + .info = NULL +}; + +struct amba_dev_id grcan_ids[] = +{ + {VENDOR_GAISLER, GAISLER_GRCAN}, + {VENDOR_GAISLER, GAISLER_GRHCAN}, + {0, 0} /* Mark end of table */ +}; + +struct amba_drv_info grcan_drv_info = +{ + { + DRVMGR_OBJ_DRV, /* Driver */ + NULL, /* Next driver */ + NULL, /* Device list */ + DRIVER_AMBAPP_GAISLER_GRCAN_ID, /* Driver ID */ + "GRCAN_DRV", /* Driver Name */ + DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ + &grcan_ops, + NULL, /* Funcs */ + 0, /* No devices yet */ + 0, + }, + &grcan_ids[0] +}; + +void grcan_register_drv (void) +{ + DBG("Registering GRCAN driver\n"); + drvmgr_drv_register(&grcan_drv_info.general); +} + +int grcan_init2(struct drvmgr_dev *dev) +{ + struct grcan_priv *priv; + + DBG("GRCAN[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); + priv = dev->priv = malloc(sizeof(struct grcan_priv)); + if ( !priv ) + return DRVMGR_NOMEM; + memset(priv, 0, sizeof(*priv)); + priv->dev = dev; + + /* This core will not find other cores, so we wait for init2() */ + + return DRVMGR_OK; +} + +int grcan_init3(struct drvmgr_dev *dev) +{ + struct grcan_priv *priv; + char prefix[32]; + rtems_status_code status; + + priv = dev->priv; + + /* Do initialization */ + + if ( grcan_driver_io_registered == 0) { + /* Register the I/O driver only once for all cores */ + if ( grcan_register_io(&grcan_driver_io_major) ) { + /* Failed to register I/O driver */ + dev->priv = NULL; + return DRVMGR_FAIL; + } + + grcan_driver_io_registered = 1; + } + + /* I/O system registered and initialized + * Now we take care of device initialization. + */ + + if ( grcan_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/grcan%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/%sgrcan%d", prefix, dev->minor_bus); + } + + /* Register Device */ + status = rtems_io_register_name(priv->devName, grcan_driver_io_major, dev->minor_drv); + if (status != RTEMS_SUCCESSFUL) { + return DRVMGR_FAIL; + } + + return DRVMGR_OK; +} + +/******************* Driver Implementation ***********************/ + +int grcan_register_io(rtems_device_major_number *m) +{ + rtems_status_code r; + + if ((r = rtems_io_register_driver(0, &grcan_driver, m)) == RTEMS_SUCCESSFUL) { + DBG("GRCAN driver successfully registered, major: %d\n", *m); + } else { + switch(r) { + case RTEMS_TOO_MANY: + printk("GRCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); + return -1; + case RTEMS_INVALID_NUMBER: + printk("GRCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); + return -1; + case RTEMS_RESOURCE_IN_USE: + printk("GRCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); + return -1; + default: + printk("GRCAN rtems_io_register_driver failed\n"); + return -1; + } + } + return 0; +} + +int grcan_device_init(struct grcan_priv *pDev) +{ + struct amba_dev_info *ambadev; + struct ambapp_core *pnpinfo; + + /* 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 = (struct grcan_regs *)pnpinfo->apb_slv->start; + pDev->minor = pDev->dev->minor_drv; + + /* Get frequency in Hz */ + if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->corefreq_hz) ) { + return -1; + } + + DBG("GRCAN frequency: %d Hz\n", pDev->corefreq_hz); + + /* Reset Hardware before attaching IRQ handler */ + grcan_hw_reset(pDev->regs); + + /* RX Semaphore created with count = 0 */ + if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'R', '0' + pDev->minor), + 0, + RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ + RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, + 0, + &pDev->rx_sem) != RTEMS_SUCCESSFUL ) { + return RTEMS_INTERNAL_ERROR; + } + + /* TX Semaphore created with count = 0 */ + if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'T', '0' + pDev->minor), + 0, + RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ + RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, + 0, + &pDev->tx_sem) != RTEMS_SUCCESSFUL ) { + return RTEMS_INTERNAL_ERROR; + } + + /* TX Empty Semaphore created with count = 0 */ + if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'E', '0' + pDev->minor), + 0, + RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ + RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, + 0, + &pDev->txempty_sem) != RTEMS_SUCCESSFUL ) { + return RTEMS_INTERNAL_ERROR; + } + + /* Device Semaphore created with count = 1 */ + if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'A', '0' + pDev->minor), + 1, + RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ + RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, + 0, + &pDev->dev_sem) != RTEMS_SUCCESSFUL ) { + return RTEMS_INTERNAL_ERROR; + } + + return 0; +} static void __inline__ grcan_hw_reset(struct grcan_regs *regs) { @@ -325,11 +453,11 @@ static rtems_device_driver grcan_start(struct grcan_priv *pDev) } /* Setup receiver */ - pDev->regs->rx0addr = MEMAREA_TO_HW((unsigned int)pDev->rx); + pDev->regs->rx0addr = (unsigned int)pDev->_rx_hw; pDev->regs->rx0size = pDev->rxbuf_size; /* Setup Transmitter */ - pDev->regs->tx0addr = MEMAREA_TO_HW((unsigned int)pDev->tx); + pDev->regs->tx0addr = (unsigned int)pDev->_tx_hw; pDev->regs->tx0size = pDev->txbuf_size; /* Setup acceptance filters */ @@ -875,7 +1003,7 @@ static int grcan_wait_txspace( IRQ_GLOBAL_DISABLE(oldLevel); - /*pDev->regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;*/ + pDev->regs->tx0ctrl = GRCAN_TXCTRL_ENABLE; size = READ_REG(&pDev->regs->tx0size); wp = READ_REG(&pDev->regs->tx0wr); @@ -972,851 +1100,720 @@ static int grcan_tx_flush(struct grcan_priv *pDev) static int grcan_alloc_buffers(struct grcan_priv *pDev, int rx, int tx) { - FUNCDBG(); - - if ( tx ) { -#ifdef STATIC_TX_BUF_ADDR - pDev->_tx = STATIC_TX_BUF_ADDR(pDev->minor); - if ( pDev->txbuf_size > STATIC_TX_BUF_SIZE ){ - pDev->txbuf_size = STATIC_TX_BUF_SIZE; - return -1; - } - /* Assume aligned buffer */ - pDev->tx = (struct grcan_msg *)pDev->_tx; -#else - pDev->_tx = malloc(pDev->txbuf_size + BUFFER_ALIGNMENT_NEEDS); - if ( !pDev->_tx ) - return -1; - - /* Align TX buffer */ - pDev->tx = (struct grcan_msg *) - (((unsigned int)pDev->_tx + (BUFFER_ALIGNMENT_NEEDS-1)) & - ~(BUFFER_ALIGNMENT_NEEDS-1)); -#endif - } - - if ( rx ) { -#ifdef STATIC_RX_BUF_ADDR - pDev->_rx = STATIC_RX_BUF_ADDR(pDev->minor); - if ( pDev->rxbuf_size > STATIC_RX_BUF_SIZE ){ - pDev->rxbuf_size = STATIC_RX_BUF_SIZE; - return -1; - } - /* Assume aligned buffer */ - pDev->rx = (struct grcan_msg *)pDev->_rx; -#else - pDev->_rx = malloc(pDev->rxbuf_size + BUFFER_ALIGNMENT_NEEDS); - if ( !pDev->_rx ) - return -1; + unsigned int adr; + FUNCDBG(); + + if ( tx ) { + adr = (unsigned int)pDev->txbuf_adr; + if (adr & 0x1) { + /* User defined "remote" address. Translate it into + * a CPU accessible address + */ + pDev->_tx_hw = (void *)(adr & ~0x1); + drvmgr_translate_check( + pDev->dev, + DMAMEM_TO_CPU, + (void *)pDev->_tx_hw, + (void **)&pDev->_tx, + pDev->txbuf_size); + pDev->tx = (struct grcan_msg *)pDev->_tx; + } else { + if (adr == 0) { + pDev->_tx = malloc(pDev->txbuf_size + + BUFFER_ALIGNMENT_NEEDS); + if (!pDev->_tx) + return -1; + } else { + /* User defined "cou-local" address. Translate + * it into a CPU accessible address + */ + pDev->_tx = (void *)adr; + } + /* Align TX buffer */ + pDev->tx = (struct grcan_msg *) + (((unsigned int)pDev->_tx + + (BUFFER_ALIGNMENT_NEEDS-1)) & + ~(BUFFER_ALIGNMENT_NEEDS-1)); + + /* Translate address into an hardware accessible + * address + */ + drvmgr_translate_check( + pDev->dev, + CPUMEM_TO_DMA, + (void *)pDev->tx, + (void **)&pDev->_tx_hw, + pDev->txbuf_size); + } + } - /* Align TX buffer */ - pDev->rx = (struct grcan_msg *) - (((unsigned int)pDev->_rx + (BUFFER_ALIGNMENT_NEEDS-1)) & - ~(BUFFER_ALIGNMENT_NEEDS-1)); -#endif - } - return 0; + if ( rx ) { + adr = (unsigned int)pDev->rxbuf_adr; + if (adr & 0x1) { + /* User defined "remote" address. Translate it into + * a CPU accessible address + */ + pDev->_rx_hw = (void *)(adr & ~0x1); + drvmgr_translate_check( + pDev->dev, + DMAMEM_TO_CPU, + (void *)pDev->_rx_hw, + (void **)&pDev->_rx, + pDev->rxbuf_size); + pDev->rx = (struct grcan_msg *)pDev->_rx; + } else { + if (adr == 0) { + pDev->_rx = malloc(pDev->rxbuf_size + + BUFFER_ALIGNMENT_NEEDS); + if (!pDev->_rx) + return -1; + } else { + /* User defined "cou-local" address. Translate + * it into a CPU accessible address + */ + pDev->_rx = (void *)adr; + } + /* Align RX buffer */ + pDev->rx = (struct grcan_msg *) + (((unsigned int)pDev->_rx + + (BUFFER_ALIGNMENT_NEEDS-1)) & + ~(BUFFER_ALIGNMENT_NEEDS-1)); + + /* Translate address into an hardware accessible + * address + */ + drvmgr_translate_check( + pDev->dev, + CPUMEM_TO_DMA, + (void *)pDev->rx, + (void **)&pDev->_rx_hw, + pDev->rxbuf_size); + } + } + return 0; } static void grcan_free_buffers(struct grcan_priv *pDev, int rx, int tx) { FUNCDBG(); -#ifndef STATIC_TX_BUF_ADDR if ( tx && pDev->_tx ){ free(pDev->_tx); pDev->_tx = NULL; pDev->tx = NULL; } -#endif -#ifndef STATIC_RX_BUF_ADDR + if ( rx && pDev->_rx ){ free(pDev->_rx); pDev->_rx = NULL; pDev->rx = NULL; } -#endif } -#if 0 -static char *almalloc(int sz) -{ - char *tmp; - tmp = calloc(1,2*sz); - tmp = (char *) (((int)tmp+sz) & ~(sz -1)); - return(tmp); -} -#endif - static rtems_device_driver grcan_initialize( rtems_device_major_number major, rtems_device_minor_number unused, void *arg ) { - int minor; - struct grcan_priv *pDev; - struct ambapp_apb_info dev; - rtems_status_code status; - char fs_name[20]; - unsigned int sys_freq_hz; - unsigned int deviceid = GAISLER_GRHCAN; - - printk("grcan_initialize()\n\r"); - - FUNCDBG(); - - /* find GRCAN cores */ - if ( !grcan_cores ) { - grcan_core_cnt = ambapp_get_number_apbslv_devices(amba_bus, VENDOR_GAISLER, - deviceid); - if ( grcan_core_cnt < 1 ){ - deviceid = GAISLER_GRCAN; - grcan_core_cnt = ambapp_get_number_apbslv_devices(amba_bus, VENDOR_GAISLER, - deviceid); - if ( grcan_core_cnt < 1 ) { - DBG("GRCAN: Using AMBA Plug&Play, found %d cores\n",grcan_core_cnt); - return RTEMS_UNSATISFIED; - } - } - DBG("GRCAN: Using AMBA Plug&Play, found %d cores\n",grcan_core_cnt); - } - -#ifdef GRCAN_MAX_CORENR - /* limit number of cores */ - if ( grcan_core_cnt > GRCAN_MAX_CORENR ) - grcan_core_cnt = GRCAN_MAX_CORENR; -#endif - - /* Allocate memory for cores */ - grcans = malloc(grcan_core_cnt * sizeof(struct grcan_priv)); - if ( !grcans ) - return RTEMS_NO_MEMORY; - memset(grcans,0,grcan_core_cnt * sizeof(struct grcan_priv)); - - /* make a local copy of device name */ - strcpy(fs_name,GRCAN_DEVNAME); - - /* Detect System Frequency from initialized timer */ -#ifndef SYS_FREQ_HZ -#if defined(LEON3) - /* LEON3: find timer address via AMBA Plug&Play info */ - { - struct ambapp_apb_info gptimer; - struct gptimer_regs *tregs; - - if (ambapp_find_apbslv (&ambapp_plb, VENDOR_GAISLER, GAISLER_GPTIMER, &gptimer) - == 1) { - tregs = (struct gptimer_regs *) gptimer.start; - sys_freq_hz = (tregs->scaler_reload + 1) * 1000 * 1000; - DBG("GRCAN: detected %dHZ system frequency\n\r", sys_freq_hz); - } else { - sys_freq_hz = 40000000; /* Default to 40MHz */ - printk("GRCAN: Failed to detect system frequency\n\r"); - } - } -#elif defined(LEON2) - /* LEON2: use hardcoded address to get to timer */ - { - LEON_Register_Map *regs = (LEON_Register_Map *) 0x80000000; - - sys_freq_hz = (regs->Scaler_Reload + 1) * 1000 * 1000; - } -#else -#error CPU not supported by driver -#endif -#else - /* Use hardcoded frequency */ - sys_freq_hz = SYS_FREQ_HZ; -#endif - - for(minor=0; minor<grcan_core_cnt; minor++){ - - pDev = &grcans[minor]; - pDev->minor = minor; - pDev->open = 0; - pDev->corefreq_hz = sys_freq_hz; - GRCAN_DEVNAME_NO(fs_name,minor); - - /* Find core address & IRQ */ - if ( !grcan_cores ) { - ambapp_find_apbslv_next(amba_bus, VENDOR_GAISLER, deviceid, &dev, minor); - pDev->irq = dev.irq; - pDev->regs = (struct grcan_regs *)dev.start; - }else{ - pDev->irq = grcan_cores[minor].irq; - pDev->regs = (struct grcan_regs *)grcan_cores[minor].base_address; - } - - printk("Registering GRCAN core at [0x%x] irq %d, minor %d as %s\n\r",pDev->regs,pDev->irq,minor,fs_name); - - status = rtems_io_register_name(fs_name, major, 0); - if (status != RTEMS_SUCCESSFUL) - rtems_fatal_error_occurred(status); - - /* Reset Hardware before attaching IRQ handler */ - grcan_hw_reset(pDev->regs); - - /* Register interrupt handler */ - GRCAN_REG_INT(GRCAN_PREFIX(_interrupt_handler), pDev->irq+GRCAN_IRQ_IRQ, pDev); - /* - GRCAN_REG_INT(grcan_interrupt_handler, pDev->irq+GRCAN_IRQ_TXSYNC, pDev); - GRCAN_REG_INT(grcan_interrupt_handler, pDev->irq+GRCAN_IRQ_RXSYNC, pDev); - */ - - /* RX Semaphore created with count = 0 */ - if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'R', '0'+minor), - 0, - RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ - RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, - 0, - &pDev->rx_sem) != RTEMS_SUCCESSFUL ) - return RTEMS_INTERNAL_ERROR; - - /* TX Semaphore created with count = 0 */ - if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'T', '0'+minor), - 0, - RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ - RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, - 0, - &pDev->tx_sem) != RTEMS_SUCCESSFUL ) - return RTEMS_INTERNAL_ERROR; - - /* TX Empty Semaphore created with count = 0 */ - if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'E', '0'+minor), - 0, - RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ - RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, - 0, - &pDev->txempty_sem) != RTEMS_SUCCESSFUL ) - return RTEMS_INTERNAL_ERROR; - - /* Device Semaphore created with count = 1 */ - if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'A', '0'+minor), - 1, - RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ - RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, - 0, - &pDev->dev_sem) != RTEMS_SUCCESSFUL ) - return RTEMS_INTERNAL_ERROR; - } - - return RTEMS_SUCCESSFUL; + return RTEMS_SUCCESSFUL; } -static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { - struct grcan_priv *pDev; - rtems_device_driver ret; +static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +{ + struct grcan_priv *pDev; + rtems_device_driver ret; + struct drvmgr_dev *dev; + union drvmgr_key_value *value; - FUNCDBG(); + FUNCDBG(); - if ( (minor < 0) || (minor>=grcan_core_cnt) ) { - DBG("Wrong minor %d\n", minor); - return RTEMS_INVALID_NUMBER; - } - - pDev = &grcans[minor]; + if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { + DBG("Wrong minor %d\n", minor); + return RTEMS_INVALID_NAME; + } + pDev = (struct grcan_priv *)dev->priv; - /* Wait until we get semaphore */ - if ( rtems_semaphore_obtain(pDev->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != - RTEMS_SUCCESSFUL ){ - return RTEMS_INTERNAL_ERROR; - } + /* Wait until we get semaphore */ + if (rtems_semaphore_obtain(pDev->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + != RTEMS_SUCCESSFUL) { + return RTEMS_INTERNAL_ERROR; + } - /* is device busy/taken? */ - if ( pDev->open ) { - ret=RTEMS_RESOURCE_IN_USE; - goto out; - } + /* is device busy/taken? */ + if ( pDev->open ) { + ret=RTEMS_RESOURCE_IN_USE; + goto out; + } - /* Mark device taken */ - pDev->open = 1; - - pDev->txblock = pDev->rxblock = 1; - pDev->txcomplete = pDev->rxcomplete = 0; - pDev->started = 0; - pDev->config_changed = 1; - pDev->config.silent = 0; - pDev->config.abort = 0; - pDev->config.selection.selection = 0; - pDev->config.selection.enable0 = 0; - pDev->config.selection.enable1 = 1; - pDev->flushing = 0; - pDev->rx = pDev->_rx = NULL; - pDev->tx = pDev->_tx = NULL; - pDev->txbuf_size = TX_BUF_SIZE; - pDev->rxbuf_size = RX_BUF_SIZE; - printk("Defaulting to rxbufsize: %d, txbufsize: %d\n",RX_BUF_SIZE,TX_BUF_SIZE); - - /* Default to accept all messages */ - pDev->afilter.mask = 0x00000000; - pDev->afilter.code = 0x00000000; - - /* Default to disable sync messages (only trigger when id is set to all ones) */ - pDev->sfilter.mask = 0xffffffff; - pDev->sfilter.code = 0x00000000; - - /* Calculate default timing register values */ - grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing); - - if ( grcan_alloc_buffers(pDev,1,1) ) { - ret=RTEMS_NO_MEMORY; - goto out; - } + /* Mark device taken */ + pDev->open = 1; + + pDev->txblock = pDev->rxblock = 1; + pDev->txcomplete = pDev->rxcomplete = 0; + pDev->started = 0; + pDev->config_changed = 1; + pDev->config.silent = 0; + pDev->config.abort = 0; + pDev->config.selection.selection = 0; + pDev->config.selection.enable0 = 0; + pDev->config.selection.enable1 = 1; + pDev->flushing = 0; + pDev->rx = pDev->_rx = NULL; + pDev->tx = pDev->_tx = NULL; + pDev->txbuf_adr = 0; + pDev->rxbuf_adr = 0; + pDev->txbuf_size = TX_BUF_SIZE; + pDev->rxbuf_size = RX_BUF_SIZE; + + /* Override default buffer sizes if available from bus resource */ + value = drvmgr_dev_key_get(pDev->dev, "txBufSize", KEY_TYPE_INT); + if ( value ) + pDev->txbuf_size = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "rxBufSize", KEY_TYPE_INT); + if ( value ) + pDev->rxbuf_size = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "txBufAdr", KEY_TYPE_POINTER); + if ( value ) + pDev->txbuf_adr = value->ptr; + + value = drvmgr_dev_key_get(pDev->dev, "rxBufAdr", KEY_TYPE_POINTER); + if ( value ) + pDev->rxbuf_adr = value->ptr; + + DBG("Defaulting to rxbufsize: %d, txbufsize: %d\n",RX_BUF_SIZE,TX_BUF_SIZE); + + /* Default to accept all messages */ + pDev->afilter.mask = 0x00000000; + pDev->afilter.code = 0x00000000; + + /* Default to disable sync messages (only trigger when id is set to all ones) */ + pDev->sfilter.mask = 0xffffffff; + pDev->sfilter.code = 0x00000000; + + /* Calculate default timing register values */ + grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing); + + if ( grcan_alloc_buffers(pDev,1,1) ) { + ret=RTEMS_NO_MEMORY; + goto out; + } - /* Clear statistics */ - memset(&pDev->stats,0,sizeof(struct grcan_stats)); + /* Clear statistics */ + memset(&pDev->stats,0,sizeof(struct grcan_stats)); - ret = RTEMS_SUCCESSFUL; + ret = RTEMS_SUCCESSFUL; out: - rtems_semaphore_release(pDev->dev_sem); - return ret; + rtems_semaphore_release(pDev->dev_sem); + return ret; } static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { - struct grcan_priv *pDev = &grcans[minor]; + struct grcan_priv *pDev; + struct drvmgr_dev *dev; - FUNCDBG(); + FUNCDBG(); - if ( pDev->started ) - grcan_stop(pDev); + if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { + return RTEMS_INVALID_NAME; + } + pDev = (struct grcan_priv *)dev->priv; - grcan_hw_reset(pDev->regs); + if ( pDev->started ) + grcan_stop(pDev); - grcan_free_buffers(pDev,1,1); + grcan_hw_reset(pDev->regs); - /* Mark Device as closed */ - pDev->open = 0; + grcan_free_buffers(pDev,1,1); - return RTEMS_SUCCESSFUL; + /* Mark Device as closed */ + pDev->open = 0; + + return RTEMS_SUCCESSFUL; } static rtems_device_driver grcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { - struct grcan_priv *pDev = &grcans[minor]; - rtems_libio_rw_args_t *rw_args; - CANMsg *dest; - unsigned int count, left; - int req_cnt; + struct grcan_priv *pDev; + struct drvmgr_dev *dev; + rtems_libio_rw_args_t *rw_args; + CANMsg *dest; + unsigned int count, left; + int req_cnt; - rw_args = (rtems_libio_rw_args_t *) arg; - dest = (CANMsg *) rw_args->buffer; - req_cnt = rw_args->count / sizeof(CANMsg); + FUNCDBG(); - FUNCDBG(); + if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { + return RTEMS_INVALID_NAME; + } + pDev = (struct grcan_priv *)dev->priv; - if ( (!dest) || (req_cnt<1) ) - return RTEMS_INVALID_NAME; + rw_args = (rtems_libio_rw_args_t *) arg; + dest = (CANMsg *) rw_args->buffer; + req_cnt = rw_args->count / sizeof(CANMsg); - if ( !pDev->started ) - return RTEMS_RESOURCE_IN_USE; + if ( (!dest) || (req_cnt<1) ) + return RTEMS_INVALID_NAME; -/* FUNCDBG("grcan_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);*/ + if ( !pDev->started ) + return RTEMS_RESOURCE_IN_USE; - count = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt); - if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){ - if ( count > 0 ) { - /* Successfully received messages (at least one) */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_SUCCESSFUL; - } + /*FUNCDBG("grcan_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);*/ - /* nothing read, shall we block? */ - if ( !pDev->rxblock ) { - /* non-blocking mode */ - rw_args->bytes_moved = 0; - return RTEMS_TIMEOUT; - } - } + count = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt); + if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){ + if ( count > 0 ) { + /* Successfully received messages (at least one) */ + rw_args->bytes_moved = count * sizeof(CANMsg); + return RTEMS_SUCCESSFUL; + } - while(count == 0 || (pDev->rxcomplete && (count!=req_cnt)) ){ + /* nothing read, shall we block? */ + if ( !pDev->rxblock ) { + /* non-blocking mode */ + rw_args->bytes_moved = 0; + return RTEMS_TIMEOUT; + } + } - if ( !pDev->rxcomplete ){ - left = 1; /* return as soon as there is one message available */ - }else{ - left = req_cnt - count; /* return as soon as all data are available */ - - /* never wait for more than the half the maximum size of the receive buffer - * Why? We need some time to copy buffer before to catch up with hw, otherwise - * we would have to copy everything when the data has been received. - */ - if ( left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE)/2) ){ - left = (pDev->rxbuf_size/GRCAN_MSG_SIZE)/2; - } - } + while(count == 0 || (pDev->rxcomplete && (count!=req_cnt)) ){ - if ( grcan_wait_rxdata(pDev,left) ) { - /* The wait has been aborted, probably due to - * the device driver has been closed by another - * thread. - */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_UNSATISFIED; - } + if ( !pDev->rxcomplete ){ + left = 1; /* return as soon as there is one message available */ + }else{ + left = req_cnt - count; /* return as soon as all data are available */ - /* Try read bytes from circular buffer */ - count += grcan_hw_read_try( - pDev, - pDev->regs, - dest+count, - req_cnt-count); - } - /* no need to unmask IRQ as IRQ Handler do that for us. */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_SUCCESSFUL; + /* never wait for more than the half the maximum size of the receive buffer + * Why? We need some time to copy buffer before to catch up with hw, + * otherwise we would have to copy everything when the data has been + * received. + */ + if ( left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE)/2) ){ + left = (pDev->rxbuf_size/GRCAN_MSG_SIZE)/2; + } + } + + if ( grcan_wait_rxdata(pDev,left) ) { + /* The wait has been aborted, probably due to + * the device driver has been closed by another + * thread. + */ + rw_args->bytes_moved = count * sizeof(CANMsg); + return RTEMS_UNSATISFIED; + } + + /* Try read bytes from circular buffer */ + count += grcan_hw_read_try( + pDev, + pDev->regs, + dest+count, + req_cnt-count); + } + /* no need to unmask IRQ as IRQ Handler do that for us. */ + rw_args->bytes_moved = count * sizeof(CANMsg); + return RTEMS_SUCCESSFUL; } static rtems_device_driver grcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { - struct grcan_priv *pDev = &grcans[minor]; - rtems_libio_rw_args_t *rw_args; - CANMsg *source; - unsigned int count, left; - int req_cnt; + struct grcan_priv *pDev; + struct drvmgr_dev *dev; + rtems_libio_rw_args_t *rw_args; + CANMsg *source; + unsigned int count, left; + int req_cnt; - DBGC(DBG_TX,"\n"); - /*FUNCDBG();*/ + DBGC(DBG_TX,"\n"); - if ( !pDev->started || pDev->config.silent || pDev->flushing ) - return RTEMS_RESOURCE_IN_USE; + if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { + return RTEMS_INVALID_NAME; + } + pDev = (struct grcan_priv *)dev->priv; - rw_args = (rtems_libio_rw_args_t *) arg; - req_cnt = rw_args->count / sizeof(CANMsg); - source = (CANMsg *) rw_args->buffer; + if ( !pDev->started || pDev->config.silent || pDev->flushing ) + return RTEMS_RESOURCE_IN_USE; - /* check proper length and buffer pointer */ - if (( req_cnt < 1) || (source == NULL) ){ - return RTEMS_INVALID_NAME; - } + rw_args = (rtems_libio_rw_args_t *) arg; + req_cnt = rw_args->count / sizeof(CANMsg); + source = (CANMsg *) rw_args->buffer; - count = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt); - if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) { - if ( count > 0 ) { - /* Successfully transmitted chars (at least one char) */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_SUCCESSFUL; - } + /* check proper length and buffer pointer */ + if (( req_cnt < 1) || (source == NULL) ){ + return RTEMS_INVALID_NAME; + } - /* nothing written, shall we block? */ - if ( !pDev->txblock ) { - /* non-blocking mode */ - rw_args->bytes_moved = 0; - return RTEMS_TIMEOUT; - } - } + count = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt); + if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) { + if ( count > 0 ) { + /* Successfully transmitted chars (at least one char) */ + rw_args->bytes_moved = count * sizeof(CANMsg); + return RTEMS_SUCCESSFUL; + } - /* if in txcomplete mode we need to transmit all chars */ - while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){ - /*** block until room to fit all or as much of transmit buffer as possible IRQ comes - * Set up a valid IRQ point so that an IRQ is received - * when we can put a chunk of data into transmit fifo - */ - if ( !pDev->txcomplete ){ - left = 1; /* wait for anything to fit buffer */ - }else{ - left = req_cnt - count; /* wait for all data to fit in buffer */ + /* nothing written, shall we block? */ + if ( !pDev->txblock ) { + /* non-blocking mode */ + rw_args->bytes_moved = 0; + return RTEMS_TIMEOUT; + } + } - /* never wait for more than the half the maximum size of the transmitt buffer - * Why? We need some time to fill buffer before hw catches up. - */ - if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){ - left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2; - } - } + /* if in txcomplete mode we need to transmit all chars */ + while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){ + /*** block until room to fit all or as much of transmit buffer as possible + * IRQ comes. Set up a valid IRQ point so that an IRQ is received + * when we can put a chunk of data into transmit fifo + */ + if ( !pDev->txcomplete ){ + left = 1; /* wait for anything to fit buffer */ + }else{ + left = req_cnt - count; /* wait for all data to fit in buffer */ + + /* never wait for more than the half the maximum size of the transmit + * buffer + * Why? We need some time to fill buffer before hw catches up. + */ + if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){ + left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2; + } + } - /* Wait until more room in transmit buffer */ - if ( grcan_wait_txspace(pDev,left) ){ - /* The wait has been aborted, probably due to - * the device driver has been closed by another - * thread. To avoid deadlock we return directly - * with error status. - */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_UNSATISFIED; - } + /* Wait until more room in transmit buffer */ + if ( grcan_wait_txspace(pDev,left) ){ + /* The wait has been aborted, probably due to + * the device driver has been closed by another + * thread. To avoid deadlock we return directly + * with error status. + */ + rw_args->bytes_moved = count * sizeof(CANMsg); + return RTEMS_UNSATISFIED; + } - if ( pDev->txerror ){ - /* Return number of bytes sent, compare write pointers */ - pDev->txerror = 0; -#if 0 + if ( pDev->txerror ){ + /* Return number of bytes sent, compare write pointers */ + pDev->txerror = 0; +#if 0 #error HANDLE AMBA error #endif - } + } - /* Try read bytes from circular buffer */ - count += grcan_hw_write_try( - pDev, - pDev->regs, - source+count, - req_cnt-count); - } - /* no need to unmask IRQ as IRQ Handler do that for us. */ + /* Try read bytes from circular buffer */ + count += grcan_hw_write_try( + pDev, + pDev->regs, + source+count, + req_cnt-count); + } + /* no need to unmask IRQ as IRQ Handler do that for us. */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_SUCCESSFUL; + rw_args->bytes_moved = count * sizeof(CANMsg); + return RTEMS_SUCCESSFUL; } static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { - struct grcan_priv *pDev = &grcans[minor]; - rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; - unsigned int *data = ioarg->buffer; - struct grcan_timing timing; - unsigned int speed; - struct grcan_selection *selection; - int tmp,ret; - rtems_device_driver status; - struct grcan_stats *stats; - struct grcan_filter *filter; - IRQ_GLOBAL_PREPARE(oldLevel); + struct grcan_priv *pDev; + struct drvmgr_dev *dev; + rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; + unsigned int *data = ioarg->buffer; + struct grcan_timing timing; + unsigned int speed; + struct grcan_selection *selection; + int tmp,ret; + rtems_device_driver status; + struct grcan_stats *stats; + struct grcan_filter *filter; + IRQ_GLOBAL_PREPARE(oldLevel); + + FUNCDBG(); + + if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { + return RTEMS_INVALID_NAME; + } + pDev = (struct grcan_priv *)dev->priv; - FUNCDBG(); + if (!ioarg) + return RTEMS_INVALID_NAME; - if (!ioarg) - return RTEMS_INVALID_NAME; + ioarg->ioctl_return = 0; + switch(ioarg->command) { + case GRCAN_IOC_START: + if ( pDev->started ) + return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - ioarg->ioctl_return = 0; - switch(ioarg->command) { - case GRCAN_IOC_START: - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ + if ( (status=grcan_start(pDev)) != RTEMS_SUCCESSFUL ){ + return status; + } + /* Read and write are now open... */ + pDev->started = 1; - if ( (status=grcan_start(pDev)) != RTEMS_SUCCESSFUL ){ - return status; - } - /* Read and write are now open... */ - pDev->started = 1; - break; + /* Register interrupt routine and enable IRQ at IRQ ctrl */ + drvmgr_interrupt_register(dev, 0, "grcan", grcan_interrupt, pDev); - case GRCAN_IOC_STOP: - if ( !pDev->started ) - return RTEMS_RESOURCE_IN_USE; + break; - grcan_stop(pDev); - pDev->started = 0; - break; + case GRCAN_IOC_STOP: + if ( !pDev->started ) + return RTEMS_RESOURCE_IN_USE; - case GRCAN_IOC_ISSTARTED: - if ( !pDev->started ) - return RTEMS_RESOURCE_IN_USE; - break; + /* Disable interrupts */ + drvmgr_interrupt_unregister(dev, 0, grcan_interrupt, pDev); - case GRCAN_IOC_FLUSH: - if ( !pDev->started || pDev->flushing || pDev->config.silent ) - return RTEMS_RESOURCE_IN_USE; - - pDev->flushing = 1; - tmp = grcan_tx_flush(pDev); - pDev->flushing = 0; - if ( tmp ) { - /* The wait has been aborted, probably due to - * the device driver has been closed by another - * thread. - */ - return RTEMS_UNSATISFIED; - } - break; + grcan_stop(pDev); + pDev->started = 0; + break; + + case GRCAN_IOC_ISSTARTED: + if ( !pDev->started ) + return RTEMS_RESOURCE_IN_USE; + break; + + case GRCAN_IOC_FLUSH: + if ( !pDev->started || pDev->flushing || pDev->config.silent ) + return RTEMS_RESOURCE_IN_USE; + + pDev->flushing = 1; + tmp = grcan_tx_flush(pDev); + pDev->flushing = 0; + if ( tmp ) { + /* The wait has been aborted, probably due to + * the device driver has been closed by another + * thread. + */ + return RTEMS_UNSATISFIED; + } + break; #if 0 - /* Set physical link */ + /* Set physical link */ case GRCAN_IOC_SET_LINK: #ifdef REDUNDANT_CHANNELS - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ + if ( pDev->started ) + return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - /* switch HW channel */ - pDev->channel = (unsigned int)ioargs->buffer; + /* switch HW channel */ + pDev->channel = (unsigned int)ioargs->buffer; #else - return RTEMS_NOT_IMPLEMENTED; + return RTEMS_NOT_IMPLEMENTED; #endif - break; + break; #endif - case GRCAN_IOC_SET_SILENT: - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; - pDev->config.silent = (int)ioarg->buffer; - pDev->config_changed = 1; - break; - - case GRCAN_IOC_SET_ABORT: - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; - pDev->config.abort = (int)ioarg->buffer; - /* This Configuration parameter doesn't need HurriCANe reset - * ==> no pDev->config_changed = 1; - */ - break; - - case GRCAN_IOC_SET_SELECTION: - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; - - selection = (struct grcan_selection *)ioarg->buffer; - if ( !selection ) - return RTEMS_INVALID_NAME; - - pDev->config.selection = *selection; - pDev->config_changed = 1; - break; - - case GRCAN_IOC_SET_RXBLOCK: - pDev->rxblock = (int)ioarg->buffer; - break; - - case GRCAN_IOC_SET_TXBLOCK: - pDev->txblock = (int)ioarg->buffer; - break; - - case GRCAN_IOC_SET_TXCOMPLETE: - pDev->txcomplete = (int)ioarg->buffer; - break; - - case GRCAN_IOC_SET_RXCOMPLETE: - pDev->rxcomplete = (int)ioarg->buffer; - break; - - case GRCAN_IOC_GET_STATS: - stats = (struct grcan_stats *)ioarg->buffer; - if ( !stats ) - return RTEMS_INVALID_NAME; - *stats = pDev->stats; - break; - - case GRCAN_IOC_CLR_STATS: - IRQ_GLOBAL_DISABLE(oldLevel); - memset(&pDev->stats,0,sizeof(struct grcan_stats)); - IRQ_GLOBAL_ENABLE(oldLevel); - break; + case GRCAN_IOC_SET_SILENT: + if ( pDev->started ) + return RTEMS_RESOURCE_IN_USE; + pDev->config.silent = (int)ioarg->buffer; + pDev->config_changed = 1; + break; + + case GRCAN_IOC_SET_ABORT: + if ( pDev->started ) + return RTEMS_RESOURCE_IN_USE; + pDev->config.abort = (int)ioarg->buffer; + /* This Configuration parameter doesn't need HurriCANe reset + * ==> no pDev->config_changed = 1; + */ + break; + + case GRCAN_IOC_SET_SELECTION: + if ( pDev->started ) + return RTEMS_RESOURCE_IN_USE; + + selection = (struct grcan_selection *)ioarg->buffer; + if ( !selection ) + return RTEMS_INVALID_NAME; + + pDev->config.selection = *selection; + pDev->config_changed = 1; + break; + + case GRCAN_IOC_SET_RXBLOCK: + pDev->rxblock = (int)ioarg->buffer; + break; + + case GRCAN_IOC_SET_TXBLOCK: + pDev->txblock = (int)ioarg->buffer; + break; + + case GRCAN_IOC_SET_TXCOMPLETE: + pDev->txcomplete = (int)ioarg->buffer; + break; + + case GRCAN_IOC_SET_RXCOMPLETE: + pDev->rxcomplete = (int)ioarg->buffer; + break; + + case GRCAN_IOC_GET_STATS: + stats = (struct grcan_stats *)ioarg->buffer; + if ( !stats ) + return RTEMS_INVALID_NAME; + *stats = pDev->stats; + break; + + case GRCAN_IOC_CLR_STATS: + IRQ_GLOBAL_DISABLE(oldLevel); + memset(&pDev->stats,0,sizeof(struct grcan_stats)); + IRQ_GLOBAL_ENABLE(oldLevel); + break; case GRCAN_IOC_SET_SPEED: - - /* cannot change speed during run mode */ - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - - /* get speed rate from argument */ - speed = (unsigned int)ioarg->buffer; - ret = grcan_calc_timing(speed,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&timing); - if ( ret ) - return RTEMS_INVALID_NAME; /* EINVAL */ - - /* save timing/speed */ - pDev->config.timing = timing; - pDev->config_changed = 1; - break; - - case GRCAN_IOC_SET_BTRS: - /* Set BTR registers manually - * Read GRCAN/HurriCANe Manual. - */ - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - - if ( !ioarg->buffer ) - return RTEMS_INVALID_NAME; - - pDev->config.timing = *(struct grcan_timing *)ioarg->buffer; - pDev->config_changed = 1; - break; - - case GRCAN_IOC_SET_AFILTER: - filter = (struct grcan_filter *)ioarg->buffer; - if ( !filter ){ - /* Disable filtering - let all messages pass */ - pDev->afilter.mask = 0x0; - pDev->afilter.code = 0x0; - }else{ - /* Save filter */ - pDev->afilter = *filter; - } - /* Set hardware acceptance filter */ - grcan_hw_accept(pDev->regs,&pDev->afilter); - break; - - case GRCAN_IOC_SET_SFILTER: - filter = (struct grcan_filter *)ioarg->buffer; - if ( !filter ){ - /* disable TX/RX SYNC filtering */ - pDev->sfilter.mask = 0xffffffff; - pDev->sfilter.mask = 0; - - /* disable Sync interrupt */ - pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ); - }else{ - /* Save filter */ - pDev->sfilter = *filter; - - /* Enable Sync interrupt */ - pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ); - } - /* Set Sync RX/TX filter */ - grcan_hw_sync(pDev->regs,&pDev->sfilter); - break; - - case GRCAN_IOC_GET_STATUS: - if ( !data ) - return RTEMS_INVALID_NAME; - /* Read out the statsu register from the GRCAN core */ - data[0] = READ_REG(&pDev->regs->stat); - break; - - default: - return RTEMS_NOT_DEFINED; - } - return RTEMS_SUCCESSFUL; -} - -#ifndef GRCAN_DONT_DECLARE_IRQ_HANDLER -/* Find what device caused the IRQ */ -static rtems_isr grcan_interrupt_handler(rtems_vector_number v) -{ - int minor=0; - while ( minor < grcan_core_cnt ){ - if ( (grcans[minor].irq+0x10) == v ){ - grcan_interrupt(&grcans[minor]); - break; - } - } + /* cannot change speed during run mode */ + if ( pDev->started ) + return RTEMS_RESOURCE_IN_USE; /* EBUSY */ + + /* get speed rate from argument */ + speed = (unsigned int)ioarg->buffer; + ret = grcan_calc_timing(speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT, &timing); + if ( ret ) + return RTEMS_INVALID_NAME; /* EINVAL */ + + /* save timing/speed */ + pDev->config.timing = timing; + pDev->config_changed = 1; + break; + + case GRCAN_IOC_SET_BTRS: + /* Set BTR registers manually + * Read GRCAN/HurriCANe Manual. + */ + if ( pDev->started ) + return RTEMS_RESOURCE_IN_USE; /* EBUSY */ + if ( !ioarg->buffer ) + return RTEMS_INVALID_NAME; + + pDev->config.timing = *(struct grcan_timing *)ioarg->buffer; + pDev->config_changed = 1; + break; + + case GRCAN_IOC_SET_AFILTER: + filter = (struct grcan_filter *)ioarg->buffer; + if ( !filter ){ + /* Disable filtering - let all messages pass */ + pDev->afilter.mask = 0x0; + pDev->afilter.code = 0x0; + }else{ + /* Save filter */ + pDev->afilter = *filter; + } + /* Set hardware acceptance filter */ + grcan_hw_accept(pDev->regs,&pDev->afilter); + break; + + case GRCAN_IOC_SET_SFILTER: + filter = (struct grcan_filter *)ioarg->buffer; + if ( !filter ){ + /* disable TX/RX SYNC filtering */ + pDev->sfilter.mask = 0xffffffff; + pDev->sfilter.mask = 0; + + /* disable Sync interrupt */ + pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ); + }else{ + /* Save filter */ + pDev->sfilter = *filter; + + /* Enable Sync interrupt */ + pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ); + } + /* Set Sync RX/TX filter */ + grcan_hw_sync(pDev->regs,&pDev->sfilter); + break; + + case GRCAN_IOC_GET_STATUS: + if ( !data ) + return RTEMS_INVALID_NAME; + /* Read out the statsu register from the GRCAN core */ + data[0] = READ_REG(&pDev->regs->stat); + break; + + default: + return RTEMS_NOT_DEFINED; + } + return RTEMS_SUCCESSFUL; } -#endif /* Handle the IRQ */ -static void grcan_interrupt(struct grcan_priv *pDev) +static void grcan_interrupt(void *arg) { - unsigned int status = READ_REG(&pDev->regs->pimsr); - unsigned int canstat = READ_REG(&pDev->regs->stat); + struct grcan_priv *pDev = arg; + unsigned int status = READ_REG(&pDev->regs->pimsr); + unsigned int canstat = READ_REG(&pDev->regs->stat); - /* Spurious IRQ call? */ - if ( !status && !canstat ) - return; + /* Spurious IRQ call? */ + if ( !status && !canstat ) + return; - FUNCDBG(); + FUNCDBG(); - /* Increment number of interrupts counter */ - pDev->stats.ints++; + /* Increment number of interrupts counter */ + pDev->stats.ints++; - if ( (status & GRCAN_ERR_IRQ) || (canstat & GRCAN_STAT_PASS) ){ - /* Error-Passive interrupt */ - pDev->stats.passive_cnt++; - } + if ( (status & GRCAN_ERR_IRQ) || (canstat & GRCAN_STAT_PASS) ){ + /* Error-Passive interrupt */ + pDev->stats.passive_cnt++; + } - if ( (status & GRCAN_OFF_IRQ) || (canstat & GRCAN_STAT_OFF) ){ - /* Bus-off condition interrupt - * The link is brought down by hardware, we wake all threads - * that is blocked in read/write calls and stop futher calls - * to read/write until user has called ioctl(fd,START,0). - */ - pDev->started = 0; - grcan_stop(pDev); /* this mask all IRQ sources */ - status=0x1ffff; /* clear all interrupts */ - goto out; - } + if ( (status & GRCAN_OFF_IRQ) || (canstat & GRCAN_STAT_OFF) ){ + /* Bus-off condition interrupt + * The link is brought down by hardware, we wake all threads + * that is blocked in read/write calls and stop futher calls + * to read/write until user has called ioctl(fd,START,0). + */ + pDev->started = 0; + grcan_stop(pDev); /* this mask all IRQ sources */ + status=0x1ffff; /* clear all interrupts */ + goto out; + } - if ( (status & GRCAN_OR_IRQ) || (canstat & GRCAN_STAT_OR) ){ - /* Over-run during reception interrupt */ - pDev->stats.overrun_cnt++; - } + if ( (status & GRCAN_OR_IRQ) || (canstat & GRCAN_STAT_OR) ){ + /* Over-run during reception interrupt */ + pDev->stats.overrun_cnt++; + } - if ( (status & GRCAN_RXAHBERR_IRQ) || - (status & GRCAN_TXAHBERR_IRQ) || - (canstat & GRCAN_STAT_AHBERR) ){ - /* RX or Tx AHB Error interrupt */ - printk("AHBERROR: status: 0x%x, canstat: 0x%x\n",status,canstat); - pDev->stats.ahberr_cnt++; - } + if ( (status & GRCAN_RXAHBERR_IRQ) || + (status & GRCAN_TXAHBERR_IRQ) || + (canstat & GRCAN_STAT_AHBERR) ){ + /* RX or Tx AHB Error interrupt */ + printk("AHBERROR: status: 0x%x, canstat: 0x%x\n",status,canstat); + pDev->stats.ahberr_cnt++; + } - if ( status & GRCAN_TXLOSS_IRQ ) { - pDev->stats.txloss_cnt++; - } + if ( status & GRCAN_TXLOSS_IRQ ) { + pDev->stats.txloss_cnt++; + } - if ( status & GRCAN_RXIRQ_IRQ ){ - /* RX IRQ pointer interrupt */ - /*printk("RxIrq 0x%x\n",status);*/ - pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ; - rtems_semaphore_release(pDev->rx_sem); - } + if ( status & GRCAN_RXIRQ_IRQ ){ + /* RX IRQ pointer interrupt */ + /*printk("RxIrq 0x%x\n",status);*/ + pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ; + rtems_semaphore_release(pDev->rx_sem); + } - if ( status & GRCAN_TXIRQ_IRQ ){ - /* TX IRQ pointer interrupt */ - pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ; - rtems_semaphore_release(pDev->tx_sem); - } + if ( status & GRCAN_TXIRQ_IRQ ){ + /* TX IRQ pointer interrupt */ + pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ; + rtems_semaphore_release(pDev->tx_sem); + } - if ( status & GRCAN_TXSYNC_IRQ ){ - /* TxSync message transmitted interrupt */ - pDev->stats.txsync_cnt++; - } + if ( status & GRCAN_TXSYNC_IRQ ){ + /* TxSync message transmitted interrupt */ + pDev->stats.txsync_cnt++; + } - if ( status & GRCAN_RXSYNC_IRQ ){ - /* RxSync message received interrupt */ - pDev->stats.rxsync_cnt++; - } + if ( status & GRCAN_RXSYNC_IRQ ){ + /* RxSync message received interrupt */ + pDev->stats.rxsync_cnt++; + } - if ( status & GRCAN_TXEMPTY_IRQ ){ - pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ; - rtems_semaphore_release(pDev->txempty_sem); - } + if ( status & GRCAN_TXEMPTY_IRQ ){ + pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ; + rtems_semaphore_release(pDev->txempty_sem); + } out: - /* Clear IRQs */ - pDev->regs->picr = status; -} - -static int grcan_register_internal(void) -{ - rtems_status_code r; - rtems_device_major_number m; - - if ((r = rtems_io_register_driver(0, &grcan_driver, &m)) != - RTEMS_SUCCESSFUL) { - switch(r) { - case RTEMS_TOO_MANY: - DBG2("failed RTEMS_TOO_MANY\n"); - break; - case RTEMS_INVALID_NUMBER: - DBG2("failed RTEMS_INVALID_NUMBER\n"); - break; - case RTEMS_RESOURCE_IN_USE: - DBG2("failed RTEMS_RESOURCE_IN_USE\n"); - break; - default: - DBG("failed %i\n",r); - break; - } - return 1; - } - DBG("Registered GRCAN on major %d\n",m); - return 0; -} - - -int grcan_register_abs(struct grcan_device_info *devices, int dev_cnt); - -/* Use custom addresses and IRQs to find hardware */ -int GRCAN_PREFIX(_register_abs)(struct grcan_device_info *devices, int dev_cnt) -{ - FUNCDBG(); - - if ( !devices || (dev_cnt<0) ) - return 1; - grcan_cores = devices; - grcan_core_cnt = dev_cnt; - - amba_bus = NULL; - return grcan_register_internal(); -} - -/* Use prescanned AMBA Plug&Play information to find all GRCAN cores */ -int GRCAN_PREFIX(_register)(struct ambapp_bus *abus) -{ - FUNCDBG(); - - if ( !abus ) - return 1; - amba_bus = abus; - grcan_cores = NULL; - grcan_core_cnt = 0; - return grcan_register_internal(); + /* Clear IRQs */ + pDev->regs->picr = status; } diff --git a/c/src/lib/libbsp/sparc/shared/can/occan.c b/c/src/lib/libbsp/sparc/shared/can/occan.c index 5920af3f52..8ce6a666bb 100644 --- a/c/src/lib/libbsp/sparc/shared/can/occan.c +++ b/c/src/lib/libbsp/sparc/shared/can/occan.c @@ -1,13 +1,11 @@ /* OC_CAN driver * * COPYRIGHT (c) 2007. - * Gaisler Research. + * 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. - * - * Author: Daniel Hellström, Gaisler Research AB, www.gaisler.com */ #include <rtems/libio.h> @@ -17,9 +15,8 @@ #include <bsp.h> #include <rtems/bspIo.h> /* printk */ -#include <leon.h> -#include <ambapp.h> -#include <grlib.h> +#include <drvmgr/drvmgr.h> +#include <drvmgr/ambapp_bus.h> #include <occan.h> /* RTEMS -> ERRNO decoding table @@ -53,27 +50,8 @@ rtems_assoc_t errno_assoc[] = { #undef OCCAN_BYTE_REGS #endif -#ifndef OCCAN_PREFIX - #define OCCAN_PREFIX(name) occan##name -#endif - -#if !defined(OCCAN_DEVNAME) || !defined(OCCAN_DEVNAME_NO) - #undef OCCAN_DEVNAME - #undef OCCAN_DEVNAME_NO - #define OCCAN_DEVNAME "/dev/occan0" - #define OCCAN_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no)) -#endif - -#ifndef OCCAN_REG_INT - #define OCCAN_REG_INT(handler,irq,arg) set_vector(handler,irq+0x10,1) - #undef OCCAN_DEFINE_INTHANDLER - #define OCCAN_DEFINE_INTHANDLER -#endif - -/* Default to 40MHz system clock */ -/*#ifndef SYS_FREQ_HZ - #define SYS_FREQ_HZ 40000000 -#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 @@ -103,7 +81,7 @@ typedef struct { } occan_fifo; /* PELICAN */ -#ifdef OCCAN_BYTE_REGS + typedef struct { unsigned char mode, @@ -149,8 +127,8 @@ typedef struct { unsigned char rx_msg_cnt; unsigned char unused1; unsigned char clkdiv; -} pelican_regs; -#else +} pelican8_regs; + typedef struct { unsigned char mode, unused0[3], @@ -196,9 +174,15 @@ typedef struct { unsigned char rx_msg_cnt,unused16[3]; unsigned char unused17[4]; unsigned char clkdiv,unused18[3]; -} pelican_regs; +} 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 @@ -217,12 +201,17 @@ typedef struct { } occan_speed_regs; typedef struct { + struct drvmgr_dev *dev; + char devName[32]; + /* 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; @@ -232,6 +221,7 @@ typedef struct { int started; int rxblk; int txblk; + int sending; unsigned int status; occan_stats stats; @@ -266,7 +256,7 @@ 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); -static void occan_interrupt(occan_priv *can); +void occan_interrupt(void *arg); #ifdef DEBUG_PRINT_REGMAP static void pelican_regadr_print(pelican_regs *regs); #endif @@ -278,33 +268,41 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev 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); -#ifdef OCCAN_DEFINE_INTHANDLER -static void occan_interrupt_handler(rtems_vector_number v); -#endif -static int can_cores; -static occan_priv *cans; -static struct ambapp_bus *amba_bus; -static unsigned int sys_freq_hz; + +#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 */ -#ifdef OCCAN_DONT_BYPASS_CACHE - #define READ_REG(address) (*(volatile unsigned char *)(address)) -#else - /* Bypass cache */ - #define READ_REG(address) _OCCAN_REG_READ((unsigned int)(address)) - static __inline__ unsigned char _OCCAN_REG_READ(unsigned int addr) { - unsigned char tmp; - __asm__ (" lduba [%1]1, %0 " - : "=r"(tmp) - : "r"(addr) - ); - return tmp; + +/* 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) + +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); } -#endif + return *(volatile unsigned char *)adr; +} -#define WRITE_REG(address,data) (*(volatile unsigned char *)(address) = (data)) +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 @@ -391,16 +389,376 @@ static unsigned int sys_freq_hz; #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, ®s->mode)); + printk(" CMD: 0x%02x\n\r",READ_REG(pDev, ®s->cmd)); + printk(" STATUS: 0x%02x\n\r",READ_REG(pDev, ®s->status)); + /*printk(" INTFLG: 0x%02x\n\r",READ_REG(pDev, ®s->intflags));*/ + printk(" INTEN: 0x%02x\n\r",READ_REG(pDev, ®s->inten)); + printk(" BTR0: 0x%02x\n\r",READ_REG(pDev, ®s->bustim0)); + printk(" BTR1: 0x%02x\n\r",READ_REG(pDev, ®s->bustim1)); + printk(" ARBCODE: 0x%02x\n\r",READ_REG(pDev, ®s->arbcode)); + printk(" ERRCODE: 0x%02x\n\r",READ_REG(pDev, ®s->errcode)); + printk(" ERRWARN: 0x%02x\n\r",READ_REG(pDev, ®s->errwarn)); + printk(" RX_ERR_CNT: 0x%02x\n\r",READ_REG(pDev, ®s->rx_err_cnt)); + printk(" TX_ERR_CNT: 0x%02x\n\r",READ_REG(pDev, ®s->tx_err_cnt)); + if ( READ_REG(pDev, ®s->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, ®s->rx_fi_xff),®s->rx_fi_xff); + printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.code[0]),(unsigned int)®s->msg.rst_accept.code[0]); + printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.code[1]),(unsigned int)®s->msg.rst_accept.code[1]); + printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.code[2]),(unsigned int)®s->msg.rst_accept.code[2]); + printk(" AMR0: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.mask[0]),(unsigned int)®s->msg.rst_accept.mask[0]); + printk(" AMR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.mask[1]),(unsigned int)®s->msg.rst_accept.mask[1]); + printk(" AMR2: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.mask[2]),(unsigned int)®s->msg.rst_accept.mask[2]); + printk(" AMR3: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.mask[3]),(unsigned int)®s->msg.rst_accept.mask[3]); + + }else{ + printk(" RXFI_XFF: 0x%02x\n\r",READ_REG(pDev, ®s->rx_fi_xff)); + } + printk(" RX_MSG_CNT: 0x%02x\n\r",READ_REG(pDev, ®s->rx_msg_cnt)); + printk(" CLKDIV: 0x%02x\n\r",READ_REG(pDev, ®s->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)®s->mode); + printk(" CMD: 0x%lx\n\r",(unsigned int)®s->cmd); + printk(" STATUS: 0x%lx\n\r",(unsigned int)®s->status); + /*printk(" INTFLG: 0x%lx\n\r",®s->intflags);*/ + printk(" INTEN: 0x%lx\n\r",(unsigned int)®s->inten); + printk(" BTR0: 0x%lx\n\r",(unsigned int)®s->bustim0); + printk(" BTR1: 0x%lx\n\r",(unsigned int)®s->bustim1); + printk(" ARBCODE: 0x%lx\n\r",(unsigned int)®s->arbcode); + printk(" ERRCODE: 0x%lx\n\r",(unsigned int)®s->errcode); + printk(" ERRWARN: 0x%lx\n\r",(unsigned int)®s->errwarn); + printk(" RX_ERR_CNT: 0x%lx\n\r",(unsigned int)®s->rx_err_cnt); + printk(" TX_ERR_CNT: 0x%lx\n\r",(unsigned int)®s->tx_err_cnt); + + /* in reset mode it is possible to read acceptance filters */ + printk(" RXFI_XFF: 0x%lx\n\r",(unsigned int)®s->rx_fi_xff); + + /* reset registers */ + printk(" ACR0: 0x%lx\n\r",(unsigned int)®s->rx_fi_xff); + printk(" ACR1: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[0]); + printk(" ACR2: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[1]); + printk(" ACR3: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[2]); + printk(" AMR0: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[0]); + printk(" AMR1: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[1]); + printk(" AMR2: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[2]); + printk(" AMR3: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[3]); + + /* TX Extended */ + printk(" EFFTX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[0]); + printk(" EFFTX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[1]); + printk(" EFFTX_ID[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[2]); + printk(" EFFTX_ID[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[3]); + + printk(" EFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[0]); + printk(" EFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[1]); + printk(" EFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[2]); + printk(" EFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[3]); + printk(" EFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[4]); + printk(" EFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[5]); + printk(" EFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[6]); + printk(" EFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[7]); + + /* RX Extended */ + printk(" EFFRX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[0]); + printk(" EFFRX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[1]); + printk(" EFFRX_ID[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[2]); + printk(" EFFRX_ID[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[3]); + + printk(" EFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[0]); + printk(" EFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[1]); + printk(" EFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[2]); + printk(" EFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[3]); + printk(" EFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[4]); + printk(" EFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[5]); + printk(" EFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[6]); + printk(" EFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[7]); + + + /* RX Extended */ + printk(" SFFRX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.id[0]); + printk(" SFFRX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.id[1]); + + printk(" SFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[0]); + printk(" SFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[1]); + printk(" SFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[2]); + printk(" SFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[3]); + printk(" SFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[4]); + printk(" SFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[5]); + printk(" SFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[6]); + printk(" SFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[7]); + + /* TX Extended */ + printk(" SFFTX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.id[0]); + printk(" SFFTX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.id[1]); + + printk(" SFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[0]); + printk(" SFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[1]); + printk(" SFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[2]); + printk(" SFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[3]); + printk(" SFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[4]); + printk(" SFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[5]); + printk(" SFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[6]); + printk(" SFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[7]); + + printk(" RX_MSG_CNT: 0x%lx\n\r",(unsigned int)®s->rx_msg_cnt); + printk(" CLKDIV: 0x%lx\n\r",(unsigned int)®s->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 */ - priv->regs->mode = PELICAN_MOD_RESET; + WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET); /* wait for core to reset complete */ /*usleep(1);*/ } static void pelican_open(occan_priv *priv){ - /* unsigned char tmp; */ int ret; /* Set defaults */ @@ -418,44 +776,45 @@ static void pelican_open(occan_priv *priv){ /* Set clock divider to extended mode, clkdiv not connected */ - priv->regs->clkdiv = (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV); + WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV)); - ret = occan_calc_speedregs(sys_freq_hz,priv->speed,&priv->timing); + 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(sys_freq_hz,priv->speed,&priv->timing); + occan_calc_speedregs(priv->sys_freq_hz, priv->speed, + &priv->timing); } /* disable all interrupts */ - priv->regs->inten = 0; + WRITE_REG(priv, &priv->regs->inten, 0); /* clear pending interrupts by reading */ - /* tmp = */ READ_REG(&priv->regs->intflags); + READ_REG(priv, &priv->regs->intflags); } static int pelican_start(occan_priv *priv){ - /* unsigned char tmp; */ /* 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); + /* 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 */ - /* tmp = */ READ_REG(&priv->regs->intflags); + READ_REG(priv, &priv->regs->intflags); /* clear error counters */ - priv->regs->rx_err_cnt = 0; - priv->regs->tx_err_cnt = 0; + 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) ){ @@ -469,15 +828,21 @@ static int pelican_start(occan_priv *priv){ /* 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->regs->bustim0),READ_REG(&priv->regs->bustim1)); + 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); - /* turn on interrupts */ - priv->regs->inten = PELICAN_IE_RX | PELICAN_IE_TX | PELICAN_IE_ERRW | - PELICAN_IE_ERRP | PELICAN_IE_BUS; + /* 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); @@ -485,17 +850,23 @@ static int pelican_start(occan_priv *priv){ #endif /* core already in reset mode, - * ¤ Exit reset mode + * ¤ Exit reset mode * ¤ Enter Single/Dual mode filtering. */ - priv->regs->mode = (priv->single_mode << 3); + 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){ +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); @@ -503,14 +874,28 @@ static void pelican_stop(occan_priv *priv){ #endif /* put core in reset mode */ - priv->regs->mode = PELICAN_MOD_RESET; + WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET); /* turn off interrupts */ - priv->regs->inten = 0; + 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, ®s->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. @@ -519,12 +904,11 @@ static void pelican_stop(occan_priv *priv){ * entering this function. */ static int pelican_send(occan_priv *can, CANMsg *msg){ - unsigned char tmp,status; + unsigned char tmp; pelican_regs *regs = can->regs; /* is there room in send buffer? */ - status = READ_REG(®s->status); - if ( !(status & PELICAN_STAT_TXBUF) ){ + if ( !pelican_tx_ready(can) ) { /* tx fifo taken, we have to wait */ return -1; } @@ -535,39 +919,40 @@ static int pelican_send(occan_priv *can, CANMsg *msg){ if ( msg->extended ){ /* Extended Frame */ - regs->rx_fi_xff = 0x80 | tmp; - WRITE_REG(®s->msg.tx_eff.id[0],(msg->id >> (5+8+8)) & 0xff); - WRITE_REG(®s->msg.tx_eff.id[1],(msg->id >> (5+8)) & 0xff); - WRITE_REG(®s->msg.tx_eff.id[2],(msg->id >> (5)) & 0xff); - WRITE_REG(®s->msg.tx_eff.id[3],(msg->id << 3) & 0xf8); + WRITE_REG(can, ®s->rx_fi_xff, 0x80 | tmp); + WRITE_REG(can, ®s->msg.tx_eff.id[0],(msg->id >> (5+8+8)) & 0xff); + WRITE_REG(can, ®s->msg.tx_eff.id[1],(msg->id >> (5+8)) & 0xff); + WRITE_REG(can, ®s->msg.tx_eff.id[2],(msg->id >> (5)) & 0xff); + WRITE_REG(can, ®s->msg.tx_eff.id[3],(msg->id << 3) & 0xf8); tmp = msg->len; while(tmp--){ - WRITE_REG(®s->msg.tx_eff.data[tmp],msg->data[tmp]); + WRITE_REG(can, ®s->msg.tx_eff.data[tmp], msg->data[tmp]); } }else{ /* Standard Frame */ - regs->rx_fi_xff = tmp; - WRITE_REG(®s->msg.tx_sff.id[0],(msg->id >> 3) & 0xff); - WRITE_REG(®s->msg.tx_sff.id[1],(msg->id << 5) & 0xe0); + WRITE_REG(can, ®s->rx_fi_xff, tmp); + WRITE_REG(can, ®s->msg.tx_sff.id[0],(msg->id >> 3) & 0xff); + WRITE_REG(can, ®s->msg.tx_sff.id[1],(msg->id << 5) & 0xe0); tmp = msg->len; while(tmp--){ - WRITE_REG(®s->msg.tx_sff.data[tmp],msg->data[tmp]); + WRITE_REG(can, ®s->msg.tx_sff.data[tmp],msg->data[tmp]); } } /* let HW know of new message */ if ( msg->sshot ){ - regs->cmd = PELICAN_CMD_TXREQ | PELICAN_CMD_ABORT; + WRITE_REG(can, ®s->cmd, PELICAN_CMD_TXREQ | PELICAN_CMD_ABORT); }else{ /* normal case -- try resend until sent */ - regs->cmd = PELICAN_CMD_TXREQ; + WRITE_REG(can, ®s->cmd, PELICAN_CMD_TXREQ); } return 0; } -static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask){ +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; @@ -582,159 +967,17 @@ static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned amask3 = (unsigned char *)&priv->regs->msg.rst_accept.mask[3]; /* Set new mask & code */ - *acode0 = acode[0]; - *acode1 = acode[1]; - *acode2 = acode[2]; - *acode3 = acode[3]; - - *amask0 = amask[0]; - *amask1 = amask[1]; - *amask2 = amask[2]; - *amask3 = amask[3]; -} - -#ifdef DEBUG -static void pelican_regs_print(pelican_regs *regs){ - printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs); - printk(" MODE: 0x%02x\n\r",READ_REG(®s->mode)); - printk(" CMD: 0x%02x\n\r",READ_REG(®s->cmd)); - printk(" STATUS: 0x%02x\n\r",READ_REG(®s->status)); - /*printk(" INTFLG: 0x%02x\n\r",READ_REG(®s->intflags));*/ - printk(" INTEN: 0x%02x\n\r",READ_REG(®s->inten)); - printk(" BTR0: 0x%02x\n\r",READ_REG(®s->bustim0)); - printk(" BTR1: 0x%02x\n\r",READ_REG(®s->bustim1)); - printk(" ARBCODE: 0x%02x\n\r",READ_REG(®s->arbcode)); - printk(" ERRCODE: 0x%02x\n\r",READ_REG(®s->errcode)); - printk(" ERRWARN: 0x%02x\n\r",READ_REG(®s->errwarn)); - printk(" RX_ERR_CNT: 0x%02x\n\r",READ_REG(®s->rx_err_cnt)); - printk(" TX_ERR_CNT: 0x%02x\n\r",READ_REG(®s->tx_err_cnt)); - if ( READ_REG(®s->mode) & PELICAN_MOD_RESET ){ - /* in reset mode it is possible to read acceptance filters */ - printk(" ACR0: 0x%02x (0x%lx)\n\r",READ_REG(®s->rx_fi_xff),®s->rx_fi_xff); - printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.code[0]),(unsigned int)®s->msg.rst_accept.code[0]); - printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.code[1]),(unsigned int)®s->msg.rst_accept.code[1]); - printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.code[2]),(unsigned int)®s->msg.rst_accept.code[2]); - printk(" AMR0: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.mask[0]),(unsigned int)®s->msg.rst_accept.mask[0]); - printk(" AMR1: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.mask[1]),(unsigned int)®s->msg.rst_accept.mask[1]); - printk(" AMR2: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.mask[2]),(unsigned int)®s->msg.rst_accept.mask[2]); - printk(" AMR3: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.mask[3]),(unsigned int)®s->msg.rst_accept.mask[3]); - - }else{ - printk(" RXFI_XFF: 0x%02x\n\r",READ_REG(®s->rx_fi_xff)); - } - printk(" RX_MSG_CNT: 0x%02x\n\r",READ_REG(®s->rx_msg_cnt)); - printk(" CLKDIV: 0x%02x\n\r",READ_REG(®s->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)®s->mode); - printk(" CMD: 0x%lx\n\r",(unsigned int)®s->cmd); - printk(" STATUS: 0x%lx\n\r",(unsigned int)®s->status); - /*printk(" INTFLG: 0x%lx\n\r",®s->intflags);*/ - printk(" INTEN: 0x%lx\n\r",(unsigned int)®s->inten); - printk(" BTR0: 0x%lx\n\r",(unsigned int)®s->bustim0); - printk(" BTR1: 0x%lx\n\r",(unsigned int)®s->bustim1); - printk(" ARBCODE: 0x%lx\n\r",(unsigned int)®s->arbcode); - printk(" ERRCODE: 0x%lx\n\r",(unsigned int)®s->errcode); - printk(" ERRWARN: 0x%lx\n\r",(unsigned int)®s->errwarn); - printk(" RX_ERR_CNT: 0x%lx\n\r",(unsigned int)®s->rx_err_cnt); - printk(" TX_ERR_CNT: 0x%lx\n\r",(unsigned int)®s->tx_err_cnt); - - /* in reset mode it is possible to read acceptance filters */ - printk(" RXFI_XFF: 0x%lx\n\r",(unsigned int)®s->rx_fi_xff); - - /* reset registers */ - printk(" ACR0: 0x%lx\n\r",(unsigned int)®s->rx_fi_xff); - printk(" ACR1: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[0]); - printk(" ACR2: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[1]); - printk(" ACR3: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[2]); - printk(" AMR0: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[0]); - printk(" AMR1: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[1]); - printk(" AMR2: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[2]); - printk(" AMR3: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[3]); - - /* TX Extended */ - printk(" EFFTX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[0]); - printk(" EFFTX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[1]); - printk(" EFFTX_ID[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[2]); - printk(" EFFTX_ID[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[3]); - - printk(" EFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[0]); - printk(" EFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[1]); - printk(" EFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[2]); - printk(" EFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[3]); - printk(" EFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[4]); - printk(" EFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[5]); - printk(" EFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[6]); - printk(" EFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[7]); - - /* RX Extended */ - printk(" EFFRX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[0]); - printk(" EFFRX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[1]); - printk(" EFFRX_ID[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[2]); - printk(" EFFRX_ID[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[3]); - - printk(" EFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[0]); - printk(" EFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[1]); - printk(" EFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[2]); - printk(" EFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[3]); - printk(" EFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[4]); - printk(" EFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[5]); - printk(" EFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[6]); - printk(" EFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[7]); - - - /* RX Extended */ - printk(" SFFRX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.id[0]); - printk(" SFFRX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.id[1]); - - printk(" SFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[0]); - printk(" SFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[1]); - printk(" SFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[2]); - printk(" SFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[3]); - printk(" SFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[4]); - printk(" SFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[5]); - printk(" SFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[6]); - printk(" SFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[7]); - - /* TX Extended */ - printk(" SFFTX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.id[0]); - printk(" SFFTX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.id[1]); - - printk(" SFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[0]); - printk(" SFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[1]); - printk(" SFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[2]); - printk(" SFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[3]); - printk(" SFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[4]); - printk(" SFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[5]); - printk(" SFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[6]); - printk(" SFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[7]); - - printk(" RX_MSG_CNT: 0x%lx\n\r",(unsigned int)®s->rx_msg_cnt); - printk(" CLKDIV: 0x%lx\n\r",(unsigned int)®s->clkdiv); - printk("-------------------\n\r"); + 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]); } -#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 /* This function calculates BTR0 and BTR1 values for a given bitrate. * @@ -744,7 +987,8 @@ static void occan_stat_print(occan_stats *stats){ * \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){ +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; @@ -827,12 +1071,14 @@ static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_ return 0; } -static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing){ +static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing) +{ if ( !timing || !priv || !priv->regs) return -1; - priv->regs->bustim0 = timing->btr0; - priv->regs->bustim1 = timing->btr1; + WRITE_REG(priv, &priv->regs->bustim0, timing->btr0); + WRITE_REG(priv, &priv->regs->bustim1, timing->btr1); + return 0; } @@ -861,7 +1107,7 @@ static int pelican_speed_auto(occan_priv *priv){ while ( (speed=pelican_speed_auto_steplist[i]) > 0){ /* Reset core */ - priv->regs->mode = PELICAN_MOD_RESET; + WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET); /* tell int handler about the auto speed detection test */ @@ -873,7 +1119,7 @@ static int pelican_speed_auto(occan_priv *priv){ pelican_set_accept(priv); /* calc timing params for this */ - if ( occan_calc_speedregs(sys_freq_hz,speed,&timing) ){ + if ( occan_calc_speedregs(priv->sys_freq_hz,speed,&timing) ){ /* failed to get good timings for this frequency * test with next */ @@ -887,13 +1133,13 @@ static int pelican_speed_auto(occan_priv *priv){ /* Empty previous messages in hardware RX fifo */ /* - while( READ_REG(&priv->regs->) ){ + while( READ_REG(priv, &priv->regs->) ){ } */ /* Clear pending interrupts */ - tmp = READ_REG(&priv->regs->intflags); + tmp = READ_REG(priv, &priv->regs->intflags); /* enable RX & ERR interrupt */ priv->regs->inten = @@ -911,176 +1157,23 @@ static int pelican_speed_auto(occan_priv *priv){ #endif } - -static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg){ - int dev_cnt,minor,subcore_cnt,devi,subi,subcores; - struct ambapp_ahb_info ambadev; - occan_priv *can; - char fs_name[20]; - rtems_status_code status; - - strcpy(fs_name,OCCAN_DEVNAME); - - /* find device on amba bus */ - dev_cnt = ambapp_get_number_ahbslv_devices(amba_bus, VENDOR_GAISLER, - GAISLER_CANAHB); - if ( dev_cnt < 1 ){ - /* Failed to find any CAN cores! */ - printk("OCCAN: Failed to find any CAN cores\n\r"); - return -1; - } - - /* Detect System Frequency from initialized timer */ -#ifndef SYS_FREQ_HZ -#if defined(LEON3) - /* LEON3: find timer address via AMBA Plug&Play info */ - { - struct ambapp_apb_info gptimer; - struct gptimer_regs *tregs; - - if ( ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, - GAISLER_GPTIMER, &gptimer) == 1 ){ - tregs = (struct gptimer_regs *)gptimer.start; - sys_freq_hz = (tregs->scaler_reload+1)*1000*1000; - DBG("OCCAN: detected %dHZ system frequency\n\r",sys_freq_hz); - }else{ - sys_freq_hz = 40000000; /* Default to 40MHz */ - printk("OCCAN: Failed to detect system frequency\n\r"); - } - - } -#elif defined(LEON2) - /* LEON2: use hardcoded address to get to timer */ - { - LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000; - sys_freq_hz = (regs->Scaler_Reload+1)*1000*1000; - } -#else - #error CPU not supported for OC_CAN driver -#endif -#else - /* Use hardcoded frequency */ - sys_freq_hz = SYS_FREQ_HZ; -#endif - - DBG("OCCAN: Detected %dHz system frequency\n\r",sys_freq_hz); - - /* OCCAN speciality: - * Mulitple cores are supported through the same amba AHB interface. - * The number of "sub cores" can be detected by decoding the AMBA - * Plug&Play version information. verion = ncores. A maximum of 8 - * sub cores are supported, each separeated with 0x100 inbetween. - * - * Now, lets detect sub cores. - */ - - for(subcore_cnt=devi=0; devi<dev_cnt; devi++){ - ambapp_find_ahbslv_next(amba_bus, VENDOR_GAISLER, - GAISLER_CANAHB, &ambadev, devi); - subcore_cnt += (ambadev.ver & 0x7)+1; - } - - printk("OCCAN: Found %d devs, totally %d sub cores\n\r",dev_cnt,subcore_cnt); - - /* allocate memory for cores */ - can_cores = subcore_cnt; - cans = calloc(subcore_cnt*sizeof(occan_priv),1); - - minor=0; - for(devi=0; devi<dev_cnt; devi++){ - - /* Get AHB device info */ - ambapp_find_ahbslv_next(amba_bus, VENDOR_GAISLER, - GAISLER_CANAHB, &ambadev, devi); - subcores = (ambadev.ver & 0x7)+1; - DBG("OCCAN: on dev %d found %d sub cores\n\r",devi,subcores); - - /* loop all subcores, at least 1 */ - for(subi=0; subi<subcores; subi++){ - can = &cans[minor]; - -#ifdef OCCAN_BYTE_REGS - /* regs is byte regs */ - can->regs = (void *)(ambadev.start[0] + OCCAN_NCORE_OFS*subi); -#else - /* regs is word regs, accessed 0x100 from base address */ - can->regs = (void *)(ambadev.start[0] + OCCAN_NCORE_OFS*subi+ OCCAN_WORD_REG_OFS); -#endif - - /* remember IRQ number */ - can->irq = ambadev.irq+subi; - - /* bind filesystem name to device */ - OCCAN_DEVNAME_NO(fs_name,minor); - printk("OCCAN: Registering %s to [%d %d] @ 0x%lx irq %d\n\r",fs_name,major,minor,(unsigned int)can->regs,can->irq); - status = rtems_io_register_name(fs_name, major, minor); - if (RTEMS_SUCCESSFUL != status ) - rtems_fatal_error_occurred(status); - - /* initialize software */ - can->open = 0; - can->rxfifo = NULL; - can->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, - &can->devsem); - if ( status != RTEMS_SUCCESSFUL ){ - printk("OCCAN: Failed to create dev semaphore for minor %d, (%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, - &can->txsem); - if ( status != RTEMS_SUCCESSFUL ){ - printk("OCCAN: Failed to create tx semaphore for minor %d, (%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, - &can->rxsem); - if ( status != RTEMS_SUCCESSFUL ){ - printk("OCCAN: Failed to create rx semaphore for minor %d, (%d)\n\r",minor,status); - return RTEMS_UNSATISFIED; - } - - /* hardware init/reset */ - pelican_init(can); - - /* Setup interrupt handler for each channel */ - OCCAN_REG_INT(OCCAN_PREFIX(_interrupt_handler), can->irq, can); - - minor++; -#ifdef DEBUG_PRINT_REGMAP - pelican_regadr_print(can->regs); -#endif - } - } - +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); - if ( minor >= can_cores ) + /* get can device */ + if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) { + DBG("Wrong minor %d\n", minor); return RTEMS_UNSATISFIED; /* NODEV */ - - /* get can device */ - can = &cans[minor]; + } + can = (occan_priv *)dev->priv; /* already opened? */ rtems_semaphore_obtain(can->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT); @@ -1126,17 +1219,24 @@ static rtems_device_driver occan_open(rtems_device_major_number major, rtems_dev return RTEMS_SUCCESSFUL; } -static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){ - occan_priv *can = &cans[minor]; +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 */ - can->regs->mode = PELICAN_MOD_RESET; + WRITE_REG(can, &can->regs->mode, PELICAN_MOD_RESET); /* free fifo memory */ occan_fifo_free(can->rxfifo); @@ -1145,16 +1245,24 @@ static rtems_device_driver occan_close(rtems_device_major_number major, rtems_de 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 = &cans[minor]; + occan_priv *can; + struct drvmgr_dev *dev; rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg; CANMsg *dstmsg, *srcmsg; rtems_interrupt_level 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*/ @@ -1205,8 +1313,9 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev DBG("OCCAN: Waiting for RX int\n\r"); - /* wait for incomming messages */ - rtems_semaphore_obtain(can->rxsem,RTEMS_WAIT,RTEMS_NO_TIMEOUT); + /* 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) ){ @@ -1244,7 +1353,8 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev } static rtems_device_driver occan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){ - occan_priv *can = &cans[minor]; + occan_priv *can; + struct drvmgr_dev *dev; rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg; CANMsg *msg,*fifo_msg; rtems_interrupt_level oldLevel; @@ -1252,6 +1362,11 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de 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 */ @@ -1293,6 +1408,11 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de 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++; @@ -1341,11 +1461,16 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de 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. - */ + * 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++; @@ -1381,15 +1506,21 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de 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 = &cans[minor]; + occan_priv *can; + struct drvmgr_dev *dev; unsigned int speed; - rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg; + 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: @@ -1400,7 +1531,7 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de /* get speed rate from argument */ speed = (unsigned int)ioarg->buffer; - ret = occan_calc_speedregs(sys_freq_hz,speed,&timing); + ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing); if ( ret ) return RTEMS_INVALID_NAME; /* EINVAL */ @@ -1479,8 +1610,8 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de return RTEMS_INVALID_NAME; /* EINVAL */ /* copy data stats into userspace buffer */ - if ( can->rxfifo ) - can->stats.rx_sw_dovr = can->rxfifo->ovcnt; + if ( can->rxfifo ) + can->stats.rx_sw_dovr = can->rxfifo->ovcnt; *dststats = can->stats; break; @@ -1543,7 +1674,9 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de 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; + /* can->started = 1; -- Is set in pelican_start due to interrupt may occur before we + * get here. + */ break; case OCCAN_IOC_STOP: @@ -1559,7 +1692,9 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de return RTEMS_SUCCESSFUL; } -static void occan_interrupt(occan_priv *can){ +void occan_interrupt(void *arg) +{ + occan_priv *can = arg; unsigned char iflags; pelican_regs *regs = can->regs; CANMsg *msg; @@ -1567,11 +1702,33 @@ static void occan_interrupt(occan_priv *can){ unsigned char tmp, errcode, arbcode; int tx_error_cnt,rx_error_cnt; - can->stats.ints++; + if ( !can->started ) + return; /* Spurious Interrupt, do nothing */ + + 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 - while ( (iflags = READ_REG(&can->regs->intflags)) != 0 ){ + 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 @@ -1579,52 +1736,53 @@ static void occan_interrupt(occan_priv *can){ /* get empty (or make room) message */ msg = occan_fifo_put_claim(can->rxfifo,1); - tmp = READ_REG(®s->rx_fi_xff); + tmp = READ_REG(can, ®s->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(®s->msg.rx_eff.id[0])<<(5+8+8) | - READ_REG(®s->msg.rx_eff.id[1])<<(5+8) | - READ_REG(®s->msg.rx_eff.id[2])<<5 | - READ_REG(®s->msg.rx_eff.id[3])>>3; + msg->id = READ_REG(can, ®s->msg.rx_eff.id[0])<<(5+8+8) | + READ_REG(can, ®s->msg.rx_eff.id[1])<<(5+8) | + READ_REG(can, ®s->msg.rx_eff.id[2])<<5 | + READ_REG(can, ®s->msg.rx_eff.id[3])>>3; + while(tmp--){ - msg->data[tmp] = READ_REG(®s->msg.rx_eff.data[tmp]); + msg->data[tmp] = READ_REG(can, ®s->msg.rx_eff.data[tmp]); } /* - msg->data[0] = READ_REG(®s->msg.rx_eff.data[0]); - msg->data[1] = READ_REG(®s->msg.rx_eff.data[1]); - msg->data[2] = READ_REG(®s->msg.rx_eff.data[2]); - msg->data[3] = READ_REG(®s->msg.rx_eff.data[3]); - msg->data[4] = READ_REG(®s->msg.rx_eff.data[4]); - msg->data[5] = READ_REG(®s->msg.rx_eff.data[5]); - msg->data[6] = READ_REG(®s->msg.rx_eff.data[6]); - msg->data[7] = READ_REG(®s->msg.rx_eff.data[7]); + msg->data[0] = READ_REG(can, ®s->msg.rx_eff.data[0]); + msg->data[1] = READ_REG(can, ®s->msg.rx_eff.data[1]); + msg->data[2] = READ_REG(can, ®s->msg.rx_eff.data[2]); + msg->data[3] = READ_REG(can, ®s->msg.rx_eff.data[3]); + msg->data[4] = READ_REG(can, ®s->msg.rx_eff.data[4]); + msg->data[5] = READ_REG(can, ®s->msg.rx_eff.data[5]); + msg->data[6] = READ_REG(can, ®s->msg.rx_eff.data[6]); + msg->data[7] = READ_REG(can, ®s->msg.rx_eff.data[7]); */ }else{ /* standard message */ - msg->id = READ_REG(®s->msg.rx_sff.id[0])<<3 | - READ_REG(®s->msg.rx_sff.id[1])>>5; + msg->id = READ_REG(can, ®s->msg.rx_sff.id[0])<<3 | + READ_REG(can, ®s->msg.rx_sff.id[1])>>5; while(tmp--){ - msg->data[tmp] = READ_REG(®s->msg.rx_sff.data[tmp]); + msg->data[tmp] = READ_REG(can, ®s->msg.rx_sff.data[tmp]); } /* - msg->data[0] = READ_REG(®s->msg.rx_sff.data[0]); - msg->data[1] = READ_REG(®s->msg.rx_sff.data[1]); - msg->data[2] = READ_REG(®s->msg.rx_sff.data[2]); - msg->data[3] = READ_REG(®s->msg.rx_sff.data[3]); - msg->data[4] = READ_REG(®s->msg.rx_sff.data[4]); - msg->data[5] = READ_REG(®s->msg.rx_sff.data[5]); - msg->data[6] = READ_REG(®s->msg.rx_sff.data[6]); - msg->data[7] = READ_REG(®s->msg.rx_sff.data[7]); + msg->data[0] = READ_REG(can, ®s->msg.rx_sff.data[0]); + msg->data[1] = READ_REG(can, ®s->msg.rx_sff.data[1]); + msg->data[2] = READ_REG(can, ®s->msg.rx_sff.data[2]); + msg->data[3] = READ_REG(can, ®s->msg.rx_sff.data[3]); + msg->data[4] = READ_REG(can, ®s->msg.rx_sff.data[4]); + msg->data[5] = READ_REG(can, ®s->msg.rx_sff.data[5]); + msg->data[6] = READ_REG(can, ®s->msg.rx_sff.data[6]); + msg->data[7] = READ_REG(can, ®s->msg.rx_sff.data[7]); */ } /* Re-Enable RX buffer for a new message */ - regs->cmd = PELICAN_CMD_RELRXBUF; + WRITE_REG(can, ®s->cmd, PELICAN_CMD_RELRXBUF); /* make message available to the user */ occan_fifo_put(can->rxfifo); @@ -1636,7 +1794,8 @@ static void occan_interrupt(occan_priv *can){ signal_rx = 1; } - if ( iflags & PELICAN_IF_TX ){ + if ( iflags & PELICAN_IF_TX ) { + /* there is room in tx fifo of HW */ if ( !occan_fifo_empty(can->txfifo) ){ @@ -1655,6 +1814,9 @@ static void occan_interrupt(occan_priv *can){ 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); @@ -1668,8 +1830,8 @@ static void occan_interrupt(occan_priv *can){ } if ( iflags & PELICAN_IF_ERRW ){ - tx_error_cnt = READ_REG(®s->tx_err_cnt); - rx_error_cnt = READ_REG(®s->rx_err_cnt); + tx_error_cnt = READ_REG(can, ®s->tx_err_cnt); + rx_error_cnt = READ_REG(can, ®s->rx_err_cnt); /* 1. if bus off tx error counter = 127 */ if ( (tx_error_cnt > 96) || (rx_error_cnt > 96) ){ @@ -1677,7 +1839,7 @@ static void occan_interrupt(occan_priv *can){ can->status |= OCCAN_STATUS_WARN; /* check reset bit for reset mode */ - if ( READ_REG(®s->mode) & PELICAN_MOD_RESET ){ + if ( READ_REG(can, ®s->mode) & PELICAN_MOD_RESET ){ /* in reset mode ==> bus off */ can->status |= OCCAN_STATUS_ERR_BUSOFF | OCCAN_STATUS_RESET; @@ -1685,7 +1847,7 @@ static void occan_interrupt(occan_priv *can){ * turn off interrupts * enter reset mode (HW already done that for us) */ - regs->inten = 0; + WRITE_REG(can, ®s->inten,0); /* Indicate that we are not started any more. * This will make write/read return with EBUSY @@ -1722,8 +1884,8 @@ static void occan_interrupt(occan_priv *can){ /* Let the error counters decide what kind of * interrupt it was. In/Out of EPassive area. */ - tx_error_cnt = READ_REG(®s->tx_err_cnt); - rx_error_cnt = READ_REG(®s->rx_err_cnt); + tx_error_cnt = READ_REG(can, ®s->tx_err_cnt); + rx_error_cnt = READ_REG(can, ®s->rx_err_cnt); if ( (tx_error_cnt > 127) || (rx_error_cnt > 127) ){ can->status |= OCCAN_STATUS_ERR_PASSIVE; @@ -1736,7 +1898,7 @@ static void occan_interrupt(occan_priv *can){ } if ( iflags & PELICAN_IF_ARB){ - arbcode = READ_REG(®s->arbcode); + arbcode = READ_REG(can, ®s->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); @@ -1747,7 +1909,7 @@ static void occan_interrupt(occan_priv *can){ * statistics. Error Register is decoded * and put into can->stats. */ - errcode = READ_REG(®s->errcode); + errcode = READ_REG(can, ®s->errcode); switch( errcode & PELICAN_ECC_CODE ){ case PELICAN_ECC_CODE_BIT: can->stats.err_bus_bit++; @@ -1788,58 +1950,12 @@ static void occan_interrupt(occan_priv *can){ } } -#ifdef OCCAN_DEFINE_INTHANDLER -static void occan_interrupt_handler(rtems_vector_number v){ - int minor; - - /* convert to */ - for(minor = 0; minor < can_cores; minor++) { - if ( v == (cans[minor].irq+0x10) ) { - occan_interrupt(&cans[minor]); - return; - } - } -} -#endif - -#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; - -int OCCAN_PREFIX(_register)(struct ambapp_bus *bus); - -int OCCAN_PREFIX(_register)(struct ambapp_bus *bus){ - rtems_status_code r; - rtems_device_major_number m; - - amba_bus = bus; - if ( !bus ) - return 1; - - if ((r = rtems_io_register_driver(0, &occan_driver, &m)) == RTEMS_SUCCESSFUL) { - DBG("OCCAN driver successfully registered, major: %d\n\r", m); - }else{ - switch(r) { - case RTEMS_TOO_MANY: - printk("OCCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break; - case RTEMS_INVALID_NUMBER: - printk("OCCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break; - case RTEMS_RESOURCE_IN_USE: - printk("OCCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break; - default: - printk("OCCAN rtems_io_register_driver failed\n\r"); - } - return 1; - } - return 0; -} - - /******************************************************************************* * FIFO IMPLEMENTATION */ -static occan_fifo *occan_fifo_create(int cnt){ +static occan_fifo *occan_fifo_create(int cnt) +{ occan_fifo *fifo; fifo = malloc(sizeof(occan_fifo)+cnt*sizeof(CANMsg)); if ( fifo ){ @@ -1854,21 +1970,25 @@ static occan_fifo *occan_fifo_create(int cnt){ return fifo; } -static void occan_fifo_free(occan_fifo *fifo){ +static void occan_fifo_free(occan_fifo *fifo) +{ if ( fifo ) free(fifo); } -static int occan_fifo_full(occan_fifo *fifo){ +static int occan_fifo_full(occan_fifo *fifo) +{ return fifo->full; } -static int occan_fifo_empty(occan_fifo *fifo){ +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){ +static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force) +{ if ( !fifo ) return NULL; @@ -1886,7 +2006,8 @@ static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force){ } /* Stage 2 - increment indexes */ -static void occan_fifo_put(occan_fifo *fifo){ +static void occan_fifo_put(occan_fifo *fifo) +{ if ( occan_fifo_full(fifo) ) return; @@ -1897,7 +2018,8 @@ static void occan_fifo_put(occan_fifo *fifo){ fifo->full = 1; } -static CANMsg *occan_fifo_claim_get(occan_fifo *fifo){ +static CANMsg *occan_fifo_claim_get(occan_fifo *fifo) +{ if ( occan_fifo_empty(fifo) ) return NULL; @@ -1906,7 +2028,8 @@ static CANMsg *occan_fifo_claim_get(occan_fifo *fifo){ } -static void occan_fifo_get(occan_fifo *fifo){ +static void occan_fifo_get(occan_fifo *fifo) +{ if ( !fifo ) return; @@ -1914,14 +2037,16 @@ static void occan_fifo_get(occan_fifo *fifo){ return; /* increment indexes */ - fifo->tail = (fifo->tail >= &fifo->base[fifo->cnt-1])? fifo->base : fifo->tail+1; + 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; +static void occan_fifo_clr(occan_fifo *fifo) +{ + fifo->full = 0; + fifo->ovcnt = 0; + fifo->head = fifo->tail = fifo->base; } -/*******************************************************************************/ +/******************************************************************************/ |