[PATCH 14/26] leon, grcan: split out GRCAN non-FD specific support in separate file

Daniel Hellstrom daniel at gaisler.com
Mon Jun 29 11:28:01 UTC 2020


---
 bsps/shared/grlib-sources.am     |   1 +
 bsps/shared/grlib/can/grcan.c    | 405 ------------------------------------
 bsps/shared/grlib/can/grcanstd.c | 435 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 436 insertions(+), 405 deletions(-)
 create mode 100644 bsps/shared/grlib/can/grcanstd.c

diff --git a/bsps/shared/grlib-sources.am b/bsps/shared/grlib-sources.am
index 10820dd..3dd3bdd 100644
--- a/bsps/shared/grlib-sources.am
+++ b/bsps/shared/grlib-sources.am
@@ -24,6 +24,7 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canbtrs.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canmux.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcan.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcanfd.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcanstd.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/occan.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/satcan.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/drvmgr/ambapp_bus.c
diff --git a/bsps/shared/grlib/can/grcan.c b/bsps/shared/grlib/can/grcan.c
index e2298d3..69f64cc 100644
--- a/bsps/shared/grlib/can/grcan.c
+++ b/bsps/shared/grlib/can/grcan.c
@@ -80,18 +80,6 @@ int state2err[4] = {
 
 static void __inline__ grcan_hw_reset(struct grcan_regs *regs);
 
-static int grcan_hw_read_try(
-	struct grcan_priv *pDev,
-	struct grcan_regs *regs,
-	CANMsg *buffer,
-	int max);
-
-static int grcan_hw_write_try(
-	struct grcan_priv *pDev,
-	struct grcan_regs *regs,
-	CANMsg *buffer,
-	int count);
-
 static void grcan_hw_config(
 	struct grcan_priv *pDev,
 	struct grcan_config *conf);
@@ -501,182 +489,6 @@ static void grcan_hw_sync(struct grcan_regs *regs, struct grcan_filter *sfilter)
 	regs->smask = sfilter->mask;
 }
 
-static int grcan_hw_read_try(
-	struct grcan_priv *pDev,
-	struct grcan_regs *regs,
-	CANMsg * buffer,
-	int max
-)
-{
-	int i, j;
-	CANMsg *dest;
-	struct grcan_msg *source, tmp;
-	unsigned int wp, rp, size, rxmax, addr;
-	int trunk_msg_cnt;
-
-	FUNCDBG();
-
-	wp = READ_REG(&regs->rx0wr);
-	rp = READ_REG(&regs->rx0rd);
-
-	/*
-	 * Due to hardware wrap around simplification write pointer will
-	 * never reach the read pointer, at least a gap of 8 bytes.
-	 * The only time they are equal is when the read pointer has
-	 * reached the write pointer (empty buffer)
-	 *
-	 */
-	if (wp != rp) {
-		/* Not empty, we have received chars...
-		 * Read as much as possible from DMA buffer
-		 */
-		size = READ_REG(&regs->rx0size);
-
-		/* Get number of bytes available in RX buffer */
-		trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
-
-		/* truncate size if user space buffer hasn't room for
-		 * all received chars.
-		 */
-		if (trunk_msg_cnt > max)
-			trunk_msg_cnt = max;
-
-		/* Read until i is 0 */
-		i = trunk_msg_cnt;
-
-		addr = (unsigned int)pDev->rx;
-		source = (struct grcan_msg *)(addr + rp);
-		dest = buffer;
-		rxmax = addr + (size - GRCAN_MSG_SIZE);
-
-		/* Read as many can messages as possible */
-		while (i > 0) {
-			/* Read CAN message from DMA buffer */
-			tmp.head[0] = READ_DMA_WORD(&source->head[0]);
-			tmp.head[1] = READ_DMA_WORD(&source->head[1]);
-			if (tmp.head[1] & 0x4) {
-				DBGC(DBG_RX, "overrun\n");
-			}
-			if (tmp.head[1] & 0x2) {
-				DBGC(DBG_RX, "bus-off mode\n");
-			}
-			if (tmp.head[1] & 0x1) {
-				DBGC(DBG_RX, "error-passive mode\n");
-			}
-			/* Convert one grcan CAN message to one "software" CAN message */
-			dest->extended = tmp.head[0] >> 31;
-			dest->rtr = (tmp.head[0] >> 30) & 0x1;
-			if (dest->extended) {
-				dest->id = tmp.head[0] & 0x3fffffff;
-			} else {
-				dest->id = (tmp.head[0] >> 18) & 0xfff;
-			}
-			dest->len = tmp.head[1] >> 28;
-			for (j = 0; j < dest->len; j++)
-				dest->data[j] = READ_DMA_BYTE(&source->data[j]);
-
-			/* wrap around if neccessary */
-			source =
-			    ((unsigned int)source >= rxmax) ?
-			    (struct grcan_msg *)addr : source + 1;
-			dest++;	/* straight user buffer */
-			i--;
-		}
-		{
-			/* A bus off interrupt may have occured after checking pDev->started */
-			SPIN_IRQFLAGS(oldLevel);
-
-			SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
-			if (pDev->started == STATE_STARTED) {
-				regs->rx0rd = (unsigned int) source - addr;
-				regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
-			} else {
-				DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
-				trunk_msg_cnt = state2err[pDev->started];
-			}
-			SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
-		}
-		return trunk_msg_cnt;
-	}
-	return 0;
-}
-
-static int grcan_hw_write_try(
-	struct grcan_priv *pDev,
-	struct grcan_regs *regs,
-	CANMsg * buffer,
-	int count
-)
-{
-	unsigned int rp, wp, size, txmax, addr;
-	int ret;
-	struct grcan_msg *dest;
-	CANMsg *source;
-	int space_left;
-	unsigned int tmp;
-	int i;
-
-	DBGC(DBG_TX, "\n");
-	/*FUNCDBG(); */
-
-	rp = READ_REG(&regs->tx0rd);
-	wp = READ_REG(&regs->tx0wr);
-	size = READ_REG(&regs->tx0size);
-
-	space_left = grcan_hw_txspace(rp, wp, size);
-
-	/* is circular fifo full? */
-	if (space_left < 1)
-		return 0;
-
-	/* Truncate size */
-	if (space_left > count)
-		space_left = count;
-	ret = space_left;
-
-	addr = (unsigned int)pDev->tx;
-
-	dest = (struct grcan_msg *)(addr + wp);
-	source = (CANMsg *) buffer;
-	txmax = addr + (size - GRCAN_MSG_SIZE);
-
-	while (space_left > 0) {
-		/* Convert and write CAN message to DMA buffer */
-		if (source->extended) {
-			tmp = (1 << 31) | (source->id & 0x3fffffff);
-		} else {
-			tmp = (source->id & 0xfff) << 18;
-		}
-		if (source->rtr)
-			tmp |= (1 << 30);
-		dest->head[0] = tmp;
-		dest->head[1] = source->len << 28;
-		for (i = 0; i < source->len; i++)
-			dest->data[i] = source->data[i];
-		source++;	/* straight user buffer */
-		dest =
-		    ((unsigned int)dest >= txmax) ?
-		    (struct grcan_msg *)addr : dest + 1;
-		space_left--;
-	}
-
-	{
-		/* A bus off interrupt may have occured after checking pDev->started */
-		SPIN_IRQFLAGS(oldLevel);
-
-		SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
-		if (pDev->started == STATE_STARTED) {
-			regs->tx0wr = (unsigned int) dest - addr;
-			regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
-		} else {
-			DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
-			ret = state2err[pDev->started];
-		}
-		SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
-	}
-	return ret;
-}
-
 int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
 {
 	unsigned int wp, rp, size, irq;
@@ -1156,176 +968,6 @@ int grcan_canfd_capable(void *d)
 	return pDev->fd_capable;
 }
 
-int grcan_read(void *d, CANMsg *msg, size_t ucount)
-{
-	struct grcan_priv *pDev = d;
-	CANMsg *dest;
-	unsigned int count, left;
-	int nread;
-	int req_cnt;
-
-	FUNCDBG();
-
-	dest = msg;
-	req_cnt = ucount;
-
-	if ( (!dest) || (req_cnt<1) )
-		return GRCAN_RET_INVARG;
-
-	if (pDev->started != STATE_STARTED) {
-		return GRCAN_RET_NOTSTARTED;
-	}
-
-	DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
-
-	nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
-	if (nread < 0) {
-		return nread;
-	}
-	count = nread;
-	if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
-		if ( count > 0 ) {
-			/* Successfully received messages (at least one) */
-			return count;
-		}
-
-		/* nothing read, shall we block? */
-		if ( !pDev->rxblock ) {
-			/* non-blocking mode */
-			return GRCAN_RET_TIMEOUT;
-		}
-	}
-
-	while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
-		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;
-			}
-		}
-
-		nread = grcan_wait_rxdata(pDev, left);
-		if (nread) {
-			/* The wait has been aborted, probably due to
-			 * the device driver has been closed by another
-			 * thread or a bus-off. Return error code.
-			 */
-			return nread;
-		}
-
-		/* Try read bytes from circular buffer */
-		nread = grcan_hw_read_try(
-				pDev,
-				pDev->regs,
-				dest+count,
-				req_cnt-count);
-
-		if (nread < 0) {
-			/* The read was aborted by bus-off. */
-			return nread;
-		}
-		count += nread;
-	}
-	/* no need to unmask IRQ as IRQ Handler do that for us. */
-	return count;
-}
-
-int grcan_write(void *d, CANMsg *msg, size_t ucount)
-{
-	struct grcan_priv *pDev = d;
-	CANMsg *source;
-	unsigned int count, left;
-	int nwritten;
-	int req_cnt;
-
-	DBGC(DBG_TX,"\n");
-
-	if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
-		return GRCAN_RET_NOTSTARTED;
-
-	req_cnt = ucount;
-	source = (CANMsg *) msg;
-
-	/* check proper length and buffer pointer */
-	if (( req_cnt < 1) || (source == NULL) ){
-		return GRCAN_RET_INVARG;
-	}
-
-	nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
-	if (nwritten < 0) {
-		return nwritten;
-	}
-	count = nwritten;
-	if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
-		if ( count > 0 ) {
-			/* Successfully transmitted chars (at least one char) */
-			return count;
-		}
-
-		/* nothing written, shall we block? */
-		if ( !pDev->txblock ) {
-			/* non-blocking mode */
-			return GRCAN_RET_TIMEOUT;
-		}
-	}
-
-	/* 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;
-			}
-		}
-
-		nwritten = grcan_wait_txspace(pDev,left);
-		/* Wait until more room in transmit buffer */
-		if ( nwritten ) {
-			/* 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.
-			 */
-			return nwritten;
-		}
-
-		/* Try read bytes from circular buffer */
-		nwritten = grcan_hw_write_try(
-			pDev,
-			pDev->regs,
-			source+count,
-			req_cnt-count);
-
-		if (nwritten < 0) {
-			/* Write was aborted by bus-off. */
-			return nwritten;
-		}
-		count += nwritten;
-	}
-	/* no need to unmask IRQ as IRQ Handler do that for us. */
-
-	return count;
-}
-
 int grcan_start(void *d)
 {
 	struct grcan_priv *pDev = d;
@@ -1552,53 +1194,6 @@ int grcan_clr_stats(void *d)
 	return 0;
 }
 
-int grcan_set_speed(void *d, unsigned int speed)
-{
-	struct grcan_priv *pDev = d;
-	struct grcan_timing timing;
-	int ret;
-
-	FUNCDBG();
-
-	/* cannot change speed during run mode */
-	if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
-		return -1;
-
-	/* get speed rate from argument */
-	ret = grlib_canbtrs_calc_timing(
-		speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
-		&grcan_btrs_ranges, (struct grlib_canbtrs_timing *)&timing);
-	if (ret)
-		return -2;
-
-	/* save timing/speed */
-	pDev->config.timing = timing;
-	pDev->config_changed = 1;
-
-	return 0;
-}
-
-int grcan_set_btrs(void *d, const struct grcan_timing *timing)
-{
-	struct grcan_priv *pDev = d;
-
-	FUNCDBG();
-
-	/* Set BTR registers manually
-	 * Read GRCAN/HurriCANe Manual.
-	 */
-	if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
-		return -1;
-
-	if ( !timing )
-		return -2;
-
-	pDev->config.timing = *timing;
-	pDev->config_changed = 1;
-
-	return 0;
-}
-
 int grcan_set_afilter(void *d, const struct grcan_filter *filter)
 {
 	struct grcan_priv *pDev = d;
diff --git a/bsps/shared/grlib/can/grcanstd.c b/bsps/shared/grlib/can/grcanstd.c
new file mode 100644
index 0000000..b92c15a
--- /dev/null
+++ b/bsps/shared/grlib/can/grcanstd.c
@@ -0,0 +1,435 @@
+/*
+ *  non-FD specific function for GRCAN driver
+ *
+ *  COPYRIGHT (c) 2007-2019.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <rtems/bspIo.h>
+
+#include <grlib/grcan.h>
+#include <grlib/canbtrs.h>
+#include <drvmgr/drvmgr.h>
+#include <grlib/ambapp_bus.h>
+#include <grlib/ambapp.h>
+
+#include <grlib/grlib_impl.h>
+#include "grcan_internal.h"
+
+/* Uncomment for debug output */
+/****************** DEBUG Definitions ********************/
+#define DBG_TX 2
+#define DBG_RX 4
+#define DBG_STATE 8
+
+#define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+#include <grlib/debug_defs.h>
+
+static int grcan_hw_read_try(
+	struct grcan_priv *pDev,
+	struct grcan_regs *regs,
+	CANMsg * buffer,
+	int max
+)
+{
+	int i, j;
+	CANMsg *dest;
+	struct grcan_msg *source, tmp;
+	unsigned int wp, rp, size, rxmax, addr;
+	int trunk_msg_cnt;
+
+	FUNCDBG();
+
+	wp = READ_REG(&regs->rx0wr);
+	rp = READ_REG(&regs->rx0rd);
+
+	/*
+	 * Due to hardware wrap around simplification write pointer will
+	 * never reach the read pointer, at least a gap of 8 bytes.
+	 * The only time they are equal is when the read pointer has
+	 * reached the write pointer (empty buffer)
+	 *
+	 */
+	if (wp != rp) {
+		/* Not empty, we have received chars...
+		 * Read as much as possible from DMA buffer
+		 */
+		size = READ_REG(&regs->rx0size);
+
+		/* Get number of bytes available in RX buffer */
+		trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
+
+		/* truncate size if user space buffer hasn't room for
+		 * all received chars.
+		 */
+		if (trunk_msg_cnt > max)
+			trunk_msg_cnt = max;
+
+		/* Read until i is 0 */
+		i = trunk_msg_cnt;
+
+		addr = (unsigned int)pDev->rx;
+		source = (struct grcan_msg *)(addr + rp);
+		dest = buffer;
+		rxmax = addr + (size - GRCAN_MSG_SIZE);
+
+		/* Read as many can messages as possible */
+		while (i > 0) {
+			/* Read CAN message from DMA buffer */
+			tmp.head[0] = READ_DMA_WORD(&source->head[0]);
+			tmp.head[1] = READ_DMA_WORD(&source->head[1]);
+			if (tmp.head[1] & 0x4) {
+				DBGC(DBG_RX, "overrun\n");
+			}
+			if (tmp.head[1] & 0x2) {
+				DBGC(DBG_RX, "bus-off mode\n");
+			}
+			if (tmp.head[1] & 0x1) {
+				DBGC(DBG_RX, "error-passive mode\n");
+			}
+			/* Convert one grcan CAN message to one "software" CAN message */
+			dest->extended = tmp.head[0] >> 31;
+			dest->rtr = (tmp.head[0] >> 30) & 0x1;
+			if (dest->extended) {
+				dest->id = tmp.head[0] & 0x3fffffff;
+			} else {
+				dest->id = (tmp.head[0] >> 18) & 0xfff;
+			}
+			dest->len = tmp.head[1] >> 28;
+			for (j = 0; j < dest->len; j++)
+				dest->data[j] = READ_DMA_BYTE(&source->data[j]);
+
+			/* wrap around if neccessary */
+			source =
+			    ((unsigned int)source >= rxmax) ?
+			    (struct grcan_msg *)addr : source + 1;
+			dest++;	/* straight user buffer */
+			i--;
+		}
+		{
+			/* A bus off interrupt may have occured after checking pDev->started */
+			SPIN_IRQFLAGS(oldLevel);
+
+			SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
+			if (pDev->started == STATE_STARTED) {
+				regs->rx0rd = (unsigned int) source - addr;
+				regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
+			} else {
+				DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
+				trunk_msg_cnt = state2err[pDev->started];
+			}
+			SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
+		}
+		return trunk_msg_cnt;
+	}
+	return 0;
+}
+
+static int grcan_hw_write_try(
+	struct grcan_priv *pDev,
+	struct grcan_regs *regs,
+	CANMsg * buffer,
+	int count
+)
+{
+	unsigned int rp, wp, size, txmax, addr;
+	int ret;
+	struct grcan_msg *dest;
+	CANMsg *source;
+	int space_left;
+	unsigned int tmp;
+	int i;
+
+	DBGC(DBG_TX, "\n");
+	/*FUNCDBG(); */
+
+	rp = READ_REG(&regs->tx0rd);
+	wp = READ_REG(&regs->tx0wr);
+	size = READ_REG(&regs->tx0size);
+
+	space_left = grcan_hw_txspace(rp, wp, size);
+
+	/* is circular fifo full? */
+	if (space_left < 1)
+		return 0;
+
+	/* Truncate size */
+	if (space_left > count)
+		space_left = count;
+	ret = space_left;
+
+	addr = (unsigned int)pDev->tx;
+
+	dest = (struct grcan_msg *)(addr + wp);
+	source = (CANMsg *) buffer;
+	txmax = addr + (size - GRCAN_MSG_SIZE);
+
+	while (space_left > 0) {
+		/* Convert and write CAN message to DMA buffer */
+		if (source->extended) {
+			tmp = (1 << 31) | (source->id & 0x3fffffff);
+		} else {
+			tmp = (source->id & 0xfff) << 18;
+		}
+		if (source->rtr)
+			tmp |= (1 << 30);
+		dest->head[0] = tmp;
+		dest->head[1] = source->len << 28;
+		for (i = 0; i < source->len; i++)
+			dest->data[i] = source->data[i];
+		source++;	/* straight user buffer */
+		dest =
+		    ((unsigned int)dest >= txmax) ?
+		    (struct grcan_msg *)addr : dest + 1;
+		space_left--;
+	}
+
+	{
+		/* A bus off interrupt may have occured after checking pDev->started */
+		SPIN_IRQFLAGS(oldLevel);
+
+		SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
+		if (pDev->started == STATE_STARTED) {
+			regs->tx0wr = (unsigned int) dest - addr;
+			regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
+		} else {
+			DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
+			ret = state2err[pDev->started];
+		}
+		SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
+	}
+	return ret;
+}
+
+
+int grcan_read(void *d, CANMsg *msg, size_t ucount)
+{
+	struct grcan_priv *pDev = d;
+	CANMsg *dest;
+	unsigned int count, left;
+	int nread;
+	int req_cnt;
+
+	FUNCDBG();
+
+	dest = msg;
+	req_cnt = ucount;
+
+	if ( (!dest) || (req_cnt<1) )
+		return GRCAN_RET_INVARG;
+
+	if (pDev->started != STATE_STARTED) {
+		return GRCAN_RET_NOTSTARTED;
+	}
+
+	DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
+
+	nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
+	if (nread < 0) {
+		return nread;
+	}
+	count = nread;
+	if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
+		if ( count > 0 ) {
+			/* Successfully received messages (at least one) */
+			return count;
+		}
+
+		/* nothing read, shall we block? */
+		if ( !pDev->rxblock ) {
+			/* non-blocking mode */
+			return GRCAN_RET_TIMEOUT;
+		}
+	}
+
+	while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
+		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;
+			}
+		}
+
+		nread = grcan_wait_rxdata(pDev, left);
+		if (nread) {
+			/* The wait has been aborted, probably due to
+			 * the device driver has been closed by another
+			 * thread or a bus-off. Return error code.
+			 */
+			return nread;
+		}
+
+		/* Try read bytes from circular buffer */
+		nread = grcan_hw_read_try(
+				pDev,
+				pDev->regs,
+				dest+count,
+				req_cnt-count);
+
+		if (nread < 0) {
+			/* The read was aborted by bus-off. */
+			return nread;
+		}
+		count += nread;
+	}
+	/* no need to unmask IRQ as IRQ Handler do that for us. */
+	return count;
+}
+
+int grcan_write(void *d, CANMsg *msg, size_t ucount)
+{
+	struct grcan_priv *pDev = d;
+	CANMsg *source;
+	unsigned int count, left;
+	int nwritten;
+	int req_cnt;
+
+	DBGC(DBG_TX,"\n");
+
+	if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
+		return GRCAN_RET_NOTSTARTED;
+
+	req_cnt = ucount;
+	source = (CANMsg *) msg;
+
+	/* check proper length and buffer pointer */
+	if (( req_cnt < 1) || (source == NULL) ){
+		return GRCAN_RET_INVARG;
+	}
+
+	nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
+	if (nwritten < 0) {
+		return nwritten;
+	}
+	count = nwritten;
+	if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
+		if ( count > 0 ) {
+			/* Successfully transmitted chars (at least one char) */
+			return count;
+		}
+
+		/* nothing written, shall we block? */
+		if ( !pDev->txblock ) {
+			/* non-blocking mode */
+			return GRCAN_RET_TIMEOUT;
+		}
+	}
+
+	/* 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;
+			}
+		}
+
+		nwritten = grcan_wait_txspace(pDev,left);
+		/* Wait until more room in transmit buffer */
+		if ( nwritten ) {
+			/* 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.
+			 */
+			return nwritten;
+		}
+
+		/* Try read bytes from circular buffer */
+		nwritten = grcan_hw_write_try(
+			pDev,
+			pDev->regs,
+			source+count,
+			req_cnt-count);
+
+		if (nwritten < 0) {
+			/* Write was aborted by bus-off. */
+			return nwritten;
+		}
+		count += nwritten;
+	}
+	/* no need to unmask IRQ as IRQ Handler do that for us. */
+
+	return count;
+}
+
+
+int grcan_set_speed(void *d, unsigned int speed)
+{
+	struct grcan_priv *pDev = d;
+	struct grcan_timing timing;
+	int ret;
+
+	FUNCDBG();
+
+	/* cannot change speed during run mode */
+	if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
+		return -1;
+
+	/* get speed rate from argument */
+	ret = grlib_canbtrs_calc_timing(
+		speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
+		&grcan_btrs_ranges, (struct grlib_canbtrs_timing *)&timing);
+	if (ret)
+		return -2;
+
+	/* save timing/speed */
+	pDev->config.timing = timing;
+	pDev->config_changed = 1;
+
+	return 0;
+}
+
+int grcan_set_btrs(void *d, const struct grcan_timing *timing)
+{
+	struct grcan_priv *pDev = d;
+
+	FUNCDBG();
+
+	/* Set BTR registers manually
+	 * Read GRCAN/HurriCANe Manual.
+	 */
+	if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
+		return -1;
+
+	if ( !timing )
+		return -2;
+
+	pDev->config.timing = *timing;
+	pDev->config_changed = 1;
+
+	return 0;
+}
-- 
2.7.4



More information about the devel mailing list