summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/can/grcan.c
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2011-12-20 16:27:54 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2015-04-17 01:10:17 +0200
commit3681925508c0da88fee6325ea35ead7b112856c6 (patch)
tree0886351bec0218ed4689c68e5442b75341cbc169 /c/src/lib/libbsp/sparc/shared/can/grcan.c
parentLEON: updated and added PCI peripherals for LEON BSPs (diff)
downloadrtems-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/grcan.c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/grcan.c1747
1 files changed, 872 insertions, 875 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;
}