Attached is the missing patch!
Wolfgang Grandegger wrote:
Hi Jan,
attached is a patch implementing the TX loopback, apart from some other
fixes and improvements. The TX loopback to foreign local sockets allows
to have a net-alike behavior of the CAN bus. Local sockets listening to
a device can receive TX messages as well. As discussed, the TX lookback
is performed when TX is done (TX done interrupt). As I still think that
it will not be used very often, I made it a configurable kernel option.
When it's selected, it's _on_ by default and it can be switched off or
on again with setsockopt() (to make the Linux Socket-CAN people happy).
As long as it's not enabled, it adds little overhead to the driver. If
you have no objections I will check it in.
Here is the ChangeLog entry:
2006-11-14 Wolfgang Grandegger <[EMAIL PROTECTED]>
* ksrc/drivers/can/rtcan_dev.h,
ksrc/drivers/can/rtcan_socket.h,
ksrc/drivers/can/rtcan_socket.c,
ksrc/drivers/can/rtcan_raw.c,
ksrc/drivers/can/rtcan_modules.c,
ksrc/drivers/can/sja1000/rtcan_sja1000.c,
ksrc/drivers/can/mscan/rtcan_mscan.c,
ksrc/drivers/can/Kconfig,
ksrc/drivers/can/Config.in,
src/utils/can/rtcansend.c,
include/rtdm/rtcan.h,: Add feature TX loopback to local sockets.
* ksrc/drivers/can/rtcan_raw.c, include/rtdm/rtcan.h:
Remove locks for the setting and reading of the RX and TX
timeout values and add a warning to the documentation.
* src/utils/rtcansend.c: use sendto() by default to avoid
binding a default filter and add option "-s" for using bind()
and send().
* src/utils/rtcanrecv.c: add option "-R" for relative
timestamps.
* ksrc/drivers/can/rtcan_internal.h: use now RTCAN_ASSERT macros
when CONFIG_XENO_DRIVERS_RTCAN_DEBUG is set.
* ksrc/drivers/can/mscan/Kconfig,
ksrc/drivers/can/sja1000/Kconfig,
ksrc/drivers/can/Kconfig: add more help for kernel parameters.
Thanks.
Wolfgang.
_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core
Index: include/rtdm/rtcan.h
===================================================================
--- include/rtdm/rtcan.h (revision 1834)
+++ include/rtdm/rtcan.h (working copy)
@@ -120,6 +120,7 @@
* - Level @b SOL_CAN_RAW : CAN RAW protocol (see @ref CAN_PROTO_RAW)
* - Option @ref CAN_RAW_FILTER : CAN filter list
* - Option @ref CAN_RAW_ERR_FILTER : CAN error mask
+ * - Option @ref CAN_RAW_TX_LOOPBACK : CAN TX loopback to local sockets
* .
* .
* @n
@@ -543,11 +544,9 @@
* - -EFAULT (It was not possible to access user space memory area at the
* specified address.)
* - -ENOMEM (Not enough memory to fulfill the operation)
- * - -EINVAL (Invalid address family, or invalid length of address structure)
- * - -ENODEV (Invalid CAN interface index)
- * - -EBADF (Socket is about to be closed)
- * - -EAGAIN (Too many receivers. Old binding (if any) is still active.
- * Close some sockets and try again.)
+ * - -EINVAL (Invalid length "optlen")
+ * - -ENOSPC (No space to store filter list, check RT-Socket-CAN kernel
+ * parameters)
* .
*/
#define CAN_RAW_FILTER 0x1
@@ -577,16 +576,39 @@
* Specific return values:
* - -EFAULT (It was not possible to access user space memory area at the
* specified address.)
- * - -ENOMEM (Not enough memory to fulfill the operation)
- * - -EINVAL (Invalid address family, or invalid length of address structure)
- * - -ENODEV (Invalid CAN interface index)
- * - -EBADF (Socket is about to be closed)
- * - -EAGAIN (Too many receivers. Old binding (if any) is still active.
- * Close some sockets and try again.)
+ * - -EINVAL (Invalid length "optlen")
* .
*/
#define CAN_RAW_ERR_FILTER 0x2
+/**
+ * CAN TX loopback
+ *
+ * The TX loopback to other local sockets can be selected with this
+ * @c setsockopt.
+ *
+ * @note The TX loopback feature must be enabled in the kernel and then
+ * the loopback to other local TX sockets is enabled by default.
+ *
+ * @n
+ * @param [in] level @b SOL_CAN_RAW
+ *
+ * @param [in] optname @b CAN_RAW_TX_LOOPBACK
+ *
+ * @param [in] optval Pointer to integer value.
+ *
+ * @param [in] optlen Size of int: sizeof(int).
+ *
+ * Environments: non-RT (RT optional)@n
+ * @n
+ * Specific return values:
+ * - -EFAULT (It was not possible to access user space memory area at the
+ * specified address.)
+ * - -EINVAL (Invalid length "optlen")
+ * - -EOPNOTSUPP (not supported, check RT-Socket-CAN kernel parameters).
+ */
+#define CAN_RAW_TX_LOOPBACK 0x3
+
/** @} */
/*!
@@ -933,6 +955,9 @@
*
* The default value for a newly created socket is an infinite timeout.
*
+ * @note The setting of the timeout value is not done atomically to avoid
+ * locks. Please set the value before receiving messages from the socket.
+ *
* @param [in] arg Pointer to @ref nanosecs_rel_t variable. The value is
* interpreted as relative timeout in nanoseconds in case
* of a positive value.
@@ -963,6 +988,9 @@
*
* The default value for a newly created socket is an infinite timeout.
*
+ * @note The setting of the timeout value is not done atomically to avoid
+ * locks. Please set the value before sending messages to the socket.
+ *
* @param [in] arg Pointer to @ref nanosecs_rel_t variable. The value is
* interpreted as relative timeout in nanoseconds in case
* of a positive value.
Index: ChangeLog
===================================================================
--- ChangeLog (revision 1834)
+++ ChangeLog (working copy)
@@ -1,3 +1,32 @@
+2006-11-14 Wolfgang Grandegger <[EMAIL PROTECTED]>
+
+ * ksrc/drivers/can/rtcan_dev.h,
+ ksrc/drivers/can/rtcan_socket.h,
+ ksrc/drivers/can/rtcan_socket.c,
+ ksrc/drivers/can/rtcan_raw.c,
+ ksrc/drivers/can/rtcan_modules.c,
+ ksrc/drivers/can/sja1000/rtcan_sja1000.c,
+ ksrc/drivers/can/mscan/rtcan_mscan.c,
+ ksrc/drivers/can/Kconfig,
+ ksrc/drivers/can/Config.in,
+ src/utils/can/rtcansend.c,
+ include/rtdm/rtcan.h,: Add feature TX loopback to local sockets.
+
+ * ksrc/drivers/can/rtcan_raw.c, include/rtdm/rtcan.h:
+ Remove locks for the setting and reading of the RX and TX timeout
+ values and add a warning to the documentation.
+
+ * src/utils/rtcansend.c: use sendto() by default to avoid binding
+ a default filter and add option "-s" for using bind() and send().
+
+ * src/utils/rtcanrecv.c: add option "-R" for relative timestamps.
+
+ * ksrc/drivers/can/rtcan_internal.h: use now RTCAN_ASSERT macros
+ when CONFIG_XENO_DRIVERS_RTCAN_DEBUG is set.
+
+ * ksrc/drivers/can/mscan/Kconfig, ksrc/drivers/can/sja1000/Kconfig,
+ ksrc/drivers/can/Kconfig: add more help for kernel parameters.
+
2006-11-12 Philippe Gerum <[EMAIL PROTECTED]>
* ksrc/nucleus/heap.c (xnheap_extend): Account for new extents
Index: src/utils/can/rtcansend.c
===================================================================
--- src/utils/can/rtcansend.c (revision 1834)
+++ src/utils/can/rtcansend.c (working copy)
@@ -26,7 +26,9 @@
" -l --loop=COUNT send message COUNT times\n"
" -c, --count message count in data[0-3]\n"
" -d, --delay=MS delay in ms (default = 1ms)\n"
+ " -s, --send use send instead of sendto\n"
" -t, --timeout=MS timeout in ms\n"
+ " -T, --tx-loopback=0|1 switch TX loopback off or on\n"
" -v, --verbose be verbose\n"
" -p, --print=MODULO print every MODULO message\n"
" -h, --help this help\n",
@@ -37,9 +39,10 @@
RT_TASK rt_task_desc;
static int s=-1, dlc=0, rtr=0, extended=0, verbose=0, loops=1, delay=1000000;
-static int count=0, print=1;
+static int count=0, print=1, use_send=0, tx_loopback=-1;
static nanosecs_rel_t timeout = 0;
static struct can_frame frame;
+static struct sockaddr_can to_addr;
void cleanup(void)
@@ -77,16 +80,21 @@
rt_task_sleep(delay);
if (count)
memcpy(&frame.data[0], &i, sizeof(i));
- ret = rt_dev_send(s, (void *)&frame, sizeof(can_frame_t), 0);
+ /* Note: sendto avoids the definiton of a receive filter list */
+ if (use_send)
+ ret = rt_dev_send(s, (void *)&frame, sizeof(can_frame_t), 0);
+ else
+ ret = rt_dev_sendto(s, (void *)&frame, sizeof(can_frame_t), 0,
+ (struct sockaddr *)&to_addr, sizeof(to_addr));
if (ret < 0) {
switch (ret) {
case -ETIMEDOUT:
if (verbose)
- printf("rt_dev_send: timed out");
+ printf("rt_dev_send(to): timed out");
break;
case -EBADF:
if (verbose)
- printf("rt_dev_send: aborted because socket was closed");
+ printf("rt_dev_send(to): aborted because socket was closed");
break;
default:
fprintf(stderr, "rt_dev_send: %s\n", strerror(-ret));
@@ -111,7 +119,6 @@
int main(int argc, char **argv)
{
- struct sockaddr_can addr;
int i, opt, ret;
struct ifreq ifr;
char name[32];
@@ -126,7 +133,9 @@
{ "print", required_argument, 0, 'p'},
{ "loop", required_argument, 0, 'l'},
{ "delay", required_argument, 0, 'd'},
+ { "send", no_argument, 0, 's'},
{ "timeout", required_argument, 0, 't'},
+ { "tx-loopbcak", required_argument, 0, 'T'},
{ 0, 0, 0, 0},
};
@@ -137,7 +146,7 @@
frame.can_id = 1;
- while ((opt = getopt_long(argc, argv, "hvi:l:red:t:cp:",
+ while ((opt = getopt_long(argc, argv, "hvi:l:red:t:cp:sT:",
long_options, NULL)) != -1) {
switch (opt) {
case 'h':
@@ -175,10 +184,18 @@
delay = strtoul(optarg, NULL, 0) * 1000000;
break;
+ case 's':
+ use_send = 1;
+ break;
+
case 't':
timeout = strtoul(optarg, NULL, 0) * 1000000;
break;
+ case 'T':
+ tx_loopback = strtoul(optarg, NULL, 0);
+ break;
+
default:
fprintf(stderr, "Unknown option %c\n", opt);
break;
@@ -205,6 +222,17 @@
}
s = ret;
+ if (tx_loopback >= 0) {
+ ret = rt_dev_setsockopt(s, SOL_CAN_RAW, CAN_RAW_TX_LOOPBACK,
+ &tx_loopback, sizeof(tx_loopback));
+ if (ret < 0) {
+ fprintf(stderr, "rt_dev_setsockopt: %s\n", strerror(-ret));
+ goto failure;
+ }
+ if (verbose)
+ printf("Using tx_loopback=%d\n", tx_loopback);
+ }
+
strncpy(ifr.ifr_name, argv[optind], IFNAMSIZ);
if (verbose)
printf("s=%d, ifr_name=%s\n", s, ifr.ifr_name);
@@ -215,13 +243,15 @@
goto failure;
}
- memset(&addr, 0, sizeof(addr));
- addr.can_ifindex = ifr.ifr_ifindex;
- addr.can_family = AF_CAN;
- ret = rt_dev_bind(s, (struct sockaddr *)&addr, sizeof(addr));
- if (ret < 0) {
- fprintf(stderr, "rt_dev_bind: %s\n", strerror(-ret));
- goto failure;
+ memset(&to_addr, 0, sizeof(to_addr));
+ to_addr.can_ifindex = ifr.ifr_ifindex;
+ to_addr.can_family = AF_CAN;
+ if (use_send) {
+ ret = rt_dev_bind(s, (struct sockaddr *)&to_addr, sizeof(to_addr));
+ if (ret < 0) {
+ fprintf(stderr, "rt_dev_bind: %s\n", strerror(-ret));
+ goto failure;
+ }
}
if (count)
Index: src/utils/can/rtcanrecv.c
===================================================================
--- src/utils/can/rtcanrecv.c (revision 1834)
+++ src/utils/can/rtcanrecv.c (working copy)
@@ -20,7 +20,8 @@
" -f --filter=id:mask[:id:mask]... apply filter\n"
" -e --error=mask receive error messages\n"
" -t, --timeout=MS timeout in ms\n"
- " -T, --timestamp with timestamp\n"
+ " -T, --timestamp with absolute timestamp\n"
+ " -R, --timestamp-rel with relative timestamp\n"
" -v, --verbose be verbose\n"
" -p, --print=MODULO print every MODULO message\n"
" -h, --help this help\n",
@@ -31,7 +32,7 @@
extern int optind, opterr, optopt;
static int s = -1, verbose = 0, print = 1;
-static nanosecs_rel_t timeout = 0, with_timestamp = 0;
+static nanosecs_rel_t timeout = 0, with_timestamp = 0, timestamp_rel = 0;
RT_TASK rt_task_desc;
@@ -87,7 +88,7 @@
socklen_t addrlen = sizeof(addr);
struct msghdr msg;
struct iovec iov;
- nanosecs_abs_t timestamp;
+ nanosecs_abs_t timestamp, timestamp_prev = 0;
if (with_timestamp) {
msg.msg_iov = &iov;
@@ -124,8 +125,13 @@
if (print && (count % print) == 0) {
printf("#%d: (%d) ", count, addr.can_ifindex);
- if (with_timestamp && msg.msg_controllen)
- printf("%lldns ", timestamp);
+ if (with_timestamp && msg.msg_controllen) {
+ if (timestamp_rel) {
+ printf("%lldns ", timestamp - timestamp_prev);
+ timestamp_prev = timestamp;
+ } else
+ printf("%lldns ", timestamp);
+ }
if (frame.can_id & CAN_ERR_FLAG)
printf("!0x%08x!", frame.can_id & CAN_ERR_MASK);
else if (frame.can_id & CAN_EFF_FLAG)
@@ -168,6 +174,7 @@
{ "error", required_argument, 0, 'e'},
{ "timeout", required_argument, 0, 't'},
{ "timestamp", no_argument, 0, 'T'},
+ { "timestamp-rel", no_argument, 0, 'R'},
{ 0, 0, 0, 0},
};
@@ -176,7 +183,7 @@
signal(SIGTERM, cleanup_and_exit);
signal(SIGINT, cleanup_and_exit);
- while ((opt = getopt_long(argc, argv, "hve:f:t:p:T",
+ while ((opt = getopt_long(argc, argv, "hve:f:t:p:RT",
long_options, NULL)) != -1) {
switch (opt) {
case 'h':
@@ -217,6 +224,8 @@
timeout = (nanosecs_rel_t)strtoul(optarg, NULL, 0) * 1000000;
break;
+ case 'R':
+ timestamp_rel = 1;
case 'T':
with_timestamp = 1;
break;
@@ -242,11 +251,11 @@
} else {
if (verbose)
printf("interface %s\n", argv[optind]);
-
+
strncpy(ifr.ifr_name, argv[optind], IFNAMSIZ);
if (verbose)
printf("s=%d, ifr_name=%s\n", s, ifr.ifr_name);
-
+
ret = rt_dev_ioctl(s, SIOCGIFINDEX, &ifr);
if (ret < 0) {
fprintf(stderr, "rt_dev_ioctl GET_IFINDEX: %s\n", strerror(-ret));
Index: ksrc/drivers/can/Kconfig
===================================================================
--- ksrc/drivers/can/Kconfig (revision 1834)
+++ ksrc/drivers/can/Kconfig (working copy)
@@ -1,35 +1,62 @@
menu "CAN drivers"
config XENO_DRIVERS_RTCAN
- depends on XENO_SKIN_RTDM
- tristate "RT-Socket-CAN, CAN raw socket interface"
- help
- RT-Socket-CAN is a real-time socket interface for CAN controllers.
+ depends on XENO_SKIN_RTDM
+ tristate "RT-Socket-CAN, CAN raw socket interface"
+ help
+ RT-Socket-CAN is a real-time socket interface for CAN controllers.
config XENO_DRIVERS_RTCAN_DEBUG
- depends on XENO_DRIVERS_RTCAN
- bool "Enable debug output"
- default y
+ depends on XENO_DRIVERS_RTCAN
+ bool "Enable debug output"
+ default y
+ help
+ This option activates debugging checks and enhanced output for the
+ RT-Socket-CAN driver. It also allows to list the hardware registers
+ of the registered CAN controllers. It is a recommended option for
+ getting started and analysing potential problems. For production
+ purposes, it should be switched off (for the sake of latency).
+
+config XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ depends on XENO_DRIVERS_RTCAN
+ bool "Enable TX loopback to local sockets"
+ default n
+ help
+
+ This options adds support for TX loopback to local sockets. Normally,
+ messages sent to the CAN bus are not visible to sockets listening to
+ the same local device. When this option is enabled, TX messages are
+ looped back locally when the transmit has been done by default. This
+ behaviour can be deactivated or reactivated with "setsockopt". Enable
+ this option, if you want to have a "net-alike" behaviour.
+
config XENO_DRIVERS_RTCAN_RXBUF_SIZE
- depends on XENO_DRIVERS_RTCAN
- int "Size of receive ring buffers (must be 2^N)"
- default 1024
+ depends on XENO_DRIVERS_RTCAN
+ int "Size of receive ring buffers (must be 2^N)"
+ default 1024
config XENO_DRIVERS_RTCAN_MAX_DEVICES
- depends on XENO_DRIVERS_RTCAN
- int "Maximum number of devices"
- default 4
+ depends on XENO_DRIVERS_RTCAN
+ int "Maximum number of devices"
+ default 4
config XENO_DRIVERS_RTCAN_MAX_RECEIVERS
- depends on XENO_DRIVERS_RTCAN
- int "Maximum number of receive filters per device"
- default 16
+ depends on XENO_DRIVERS_RTCAN
+ int "Maximum number of receive filters per device"
+ default 16
+ help
+ The driver maintains a receive filter list per device for fast access.
+
config XENO_DRIVERS_RTCAN_VIRT
depends on XENO_DRIVERS_RTCAN
tristate "Virtual CAN bus driver"
+ help
+ This driver provides two CAN ports that are virtually interconnected.
+ More ports can be enabled with the module parameter "devices".
+
source drivers/xenomai/can/mscan/Kconfig
source drivers/xenomai/can/sja1000/Kconfig
Index: ksrc/drivers/can/rtcan_internal.h
===================================================================
--- ksrc/drivers/can/rtcan_internal.h (revision 1834)
+++ ksrc/drivers/can/rtcan_internal.h (working copy)
@@ -34,10 +34,9 @@
#define LIST_POISON1 ((void *) 0x0)
#endif
-#ifdef CONFIG_RTCAN_CHECKED
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_DEBUG
#define RTCAN_ASSERT(expr, func) \
- if (!(expr)) \
- { \
+ if (!(expr)) { \
rtdm_printk("Assertion failed! %s:%s:%d %s\n", \
__FILE__, __FUNCTION__, __LINE__, (#expr)); \
func \
Index: ksrc/drivers/can/rtcan_dev.h
===================================================================
--- ksrc/drivers/can/rtcan_dev.h (revision 1834)
+++ ksrc/drivers/can/rtcan_dev.h (working copy)
@@ -141,7 +141,11 @@
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_root;
-#endif
+#endif
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ struct rtcan_skb tx_skb;
+ struct rtcan_socket *tx_socket;
+#endif /* CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK */
};
Index: ksrc/drivers/can/rtcan_module.c
===================================================================
--- ksrc/drivers/can/rtcan_module.c (revision 1834)
+++ ksrc/drivers/can/rtcan_module.c (working copy)
@@ -176,7 +176,11 @@
* 0 rtcan0 1 0x00010 1234567890 1234567890 1234567890
*/
if (!RTCAN_PROC_PRINT("fd Name___________ Filter ErrMask "
- "RX_Timeout_ns TX_Timeout_ns RX_BufFull\n"))
+ "RX_Timeout_ns TX_Timeout_ns RX_BufFull") ||
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ !RTCAN_PROC_PRINT(" TX_Loopback") ||
+#endif
+ !RTCAN_PROC_PRINT("\n"))
goto done;
rtdm_lock_get_irqsave(&rtcan_recv_list_lock, lock_ctx);
@@ -196,10 +200,14 @@
}
rtcan_get_timeout_name(sock->tx_timeout, tx_timeout, 20);
rtcan_get_timeout_name(sock->rx_timeout, rx_timeout, 20);
- if(!RTCAN_PROC_PRINT("%2d %-15s %6d 0x%05x %13s %13s %10d\n",
- context->fd, name, sock->flistlen,
- sock->err_mask, rx_timeout, tx_timeout,
- sock->rx_buf_full))
+ if (!RTCAN_PROC_PRINT("%2d %-15s %6d 0x%05x %13s %13s %10d",
+ context->fd, name, sock->flistlen,
+ sock->err_mask, rx_timeout, tx_timeout,
+ sock->rx_buf_full) ||
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ !RTCAN_PROC_PRINT(" %11d", sock->tx_loopback) ||
+#endif
+ !RTCAN_PROC_PRINT("\n"))
break;
}
Index: ksrc/drivers/can/rtcan_socket.c
===================================================================
--- ksrc/drivers/can/rtcan_socket.c (revision 1834)
+++ ksrc/drivers/can/rtcan_socket.c (working copy)
@@ -48,6 +48,9 @@
sock->flist = NULL;
sock->err_mask = 0;
sock->rx_buf_full = 0;
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ sock->tx_loopback = 1;
+#endif
sock->tx_timeout = RTDM_TIMEOUT_INFINITE;
sock->rx_timeout = RTDM_TIMEOUT_INFINITE;
Index: ksrc/drivers/can/rtcan_raw.c
===================================================================
--- ksrc/drivers/can/rtcan_raw.c (revision 1834)
+++ ksrc/drivers/can/rtcan_raw.c (working copy)
@@ -68,7 +68,7 @@
}
-static inline void rtcan_rcv_deliver(struct rtcan_recv *recv_listener,
+static void rtcan_rcv_deliver(struct rtcan_recv *recv_listener,
struct rtcan_skb *skb)
{
int size_free;
@@ -152,7 +152,50 @@
}
}
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+static void rtcan_tx_push(struct rtcan_device *dev, struct rtcan_socket *sock,
+ can_frame_t *frame)
+{
+ struct rtcan_rb_frame *rb_frame = &dev->tx_skb.rb_frame;
+
+ RTCAN_ASSERT(dev->tx_socket == 0,
+ rtdm_printk("(%d) TX skb still in use", dev->ifindex););
+
+ rb_frame->can_id = frame->can_id;
+ rb_frame->can_dlc = frame->can_dlc;
+ dev->tx_skb.rb_frame_size = EMPTY_RB_FRAME_SIZE;
+ if (frame->can_dlc && !(frame->can_id & CAN_RTR_FLAG)) {
+ memcpy(rb_frame->data, frame->data, frame->can_dlc);
+ dev->tx_skb.rb_frame_size += frame->can_dlc;
+ }
+ rb_frame->can_ifindex = dev->ifindex;
+ dev->tx_socket = sock;
+}
+
+void rtcan_tx_loopback(struct rtcan_device *dev)
+{
+ /* Entry in reception list, begin with head */
+ struct rtcan_recv *recv_listener = dev->recv_list;
+ struct rtcan_rb_frame *frame = &dev->tx_skb.rb_frame;
+
+ while (recv_listener != NULL) {
+ dev->rx_count++;
+ if ((dev->tx_socket != recv_listener->sock) &&
+ rtcan_accept_msg(frame->can_id, &recv_listener->can_filter)) {
+ recv_listener->match_count++;
+ rtcan_rcv_deliver(recv_listener, &dev->tx_skb);
+ }
+ recv_listener = recv_listener->next;
+ }
+ dev->tx_socket = NULL;
+}
+
+EXPORT_SYMBOL(rtcan_tx_loopback);
+
+#endif /* CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK */
+
+
int rtcan_raw_socket(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info, int protocol)
{
@@ -252,7 +295,7 @@
rtdm_lockctx_t lock_ctx;
can_err_mask_t err_mask;
int flistlen;
- int ret = 0;
+ int val, ret = 0;
if (so->level != SOL_CAN_RAW)
return -ENOPROTOOPT;
@@ -304,7 +347,7 @@
break;
case CAN_RAW_ERR_FILTER:
-
+
if (so->optlen != sizeof(can_err_mask_t))
return -EINVAL;
@@ -321,11 +364,31 @@
rtdm_lock_put_irqrestore(&rtcan_recv_list_lock, lock_ctx);
break;
-
+
+ case CAN_RAW_TX_LOOPBACK:
+
+ if (so->optlen != sizeof(int))
+ return -EINVAL;
+
+ if (user_info) {
+ if (!rtdm_read_user_ok(user_info, so->optval, so->optlen) ||
+ rtdm_copy_from_user(user_info, &val, so->optval, so->optlen))
+ return -EFAULT;
+ } else
+ memcpy(&val, so->optval, so->optlen);
+
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ sock->tx_loopback = val;
+#else
+ if (val)
+ return -EOPNOTSUPP;
+#endif
+ break;
+
default:
ret = -ENOPROTOOPT;
}
-
+
return ret;
}
@@ -334,7 +397,6 @@
rtdm_user_info_t *user_info, int request, void *arg)
{
int ret = 0;
- rtdm_lockctx_t lock_ctx;
switch (request) {
case _RTIOC_BIND: {
@@ -422,20 +484,11 @@
}
/* Now the differences begin between the requests. */
- if (request == RTCAN_RTIOC_RCV_TIMEOUT) {
- rtdm_lock_get_irqsave(&rtcan_socket_lock, lock_ctx);
-
+ if (request == RTCAN_RTIOC_RCV_TIMEOUT)
sock->rx_timeout = *timeout;
-
- rtdm_lock_put_irqrestore(&rtcan_socket_lock, lock_ctx);
- } else {
- rtdm_lock_get_irqsave(&rtcan_socket_lock, lock_ctx);
-
+ else
sock->tx_timeout = *timeout;
- rtdm_lock_put_irqrestore(&rtcan_socket_lock, lock_ctx);
- }
-
break;
}
@@ -554,13 +607,8 @@
/* Set RX timeout */
- rtdm_lock_get_irqsave(&rtcan_socket_lock, lock_ctx);
-
timeout = (flags & MSG_DONTWAIT) ? RTDM_TIMEOUT_NONE : sock->rx_timeout;
- rtdm_lock_put_irqrestore(&rtcan_socket_lock, lock_ctx);
-
-
/* Fetch message (ok, try it ...) */
ret = rtdm_sem_timeddown(&sock->recv_sem, timeout, NULL);
@@ -836,14 +884,9 @@
if ((dev = rtcan_dev_get_by_index(ifindex)) == NULL)
return -ENXIO;
-
- rtdm_lock_get_irqsave(&rtcan_socket_lock, lock_ctx);
timeout = (flags & MSG_DONTWAIT) ? RTDM_TIMEOUT_NONE : sock->tx_timeout;
- rtdm_lock_put_irqrestore(&rtcan_socket_lock, lock_ctx);
-
-
tx_wait.rt_task = rtdm_task_current();
/* If socket was not closed recently, register the task at the
@@ -894,6 +937,12 @@
/* We got access */
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ /* Push message onto stack for loopback when TX done */
+ if (sock->tx_loopback)
+ rtcan_tx_push(dev, sock, frame);
+#endif /* CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK */
+
rtdm_lock_get_irqsave(&dev->device_lock, lock_ctx);
/* Controller should be operating */
@@ -909,7 +958,7 @@
dev->tx_count++;
if ((ret = dev->hard_start_xmit(dev, frame)) != 0)
goto send_out2;
-
+
/* Return number of bytes sent upon successful completion */
ret = sizeof(can_frame_t);
Index: ksrc/drivers/can/mscan/Kconfig
===================================================================
--- ksrc/drivers/can/mscan/Kconfig (revision 1834)
+++ ksrc/drivers/can/mscan/Kconfig (working copy)
@@ -1,32 +1,39 @@
config XENO_DRIVERS_RTCAN_MSCAN
- depends on XENO_DRIVERS_RTCAN && PPC_MPC52xx
- tristate "MSCAN driver for MPC52xx"
- default n
-
+ depends on XENO_DRIVERS_RTCAN && PPC_MPC52xx
+ tristate "MSCAN driver for MPC52xx"
+ default n
+
config XENO_DRIVERS_RTCAN_MSCAN_1
- depends on XENO_DRIVERS_RTCAN_MSCAN
- bool "Enable CAN 1"
- default y
-
+ depends on XENO_DRIVERS_RTCAN_MSCAN
+ bool "Enable CAN 1"
+ default y
+
config XENO_DRIVERS_RTCAN_MSCAN_2
- depends on XENO_DRIVERS_RTCAN_MSCAN
- bool "Enable CAN 2"
- default y
-
+ depends on XENO_DRIVERS_RTCAN_MSCAN
+ bool "Enable CAN 2"
+ default y
+
config XENO_DRIVERS_RTCAN_MSCAN_CLOCK
- depends on XENO_DRIVERS_RTCAN_MSCAN
- int "Clock Frequency in Hz"
- default 66000000
-
+ depends on XENO_DRIVERS_RTCAN_MSCAN
+ int "Clock Frequency in Hz"
+ default 66000000
+ help
+
+ The MSCAN driver selects the oscillator clock (SYS_XTAL_IN) as clock
+ source for MSCAN, which is typically 33 MHz. Due to a hardware bug on
+ the MPC5200 Rev. A chips, the IP bus clock (IP_CLK) is used instead,
+ which is typically 66 or 132 MHz.
+
choice
depends on XENO_DRIVERS_RTCAN_MSCAN
prompt "Pin Configuration"
default I2C1/TMR01
+ help
-config XENO_DRIVERS_RTCAN_MSCAN_ALT
+config XENO_DRIVERS_RTCAN_MSCAN_ALT
bool "CAN 1 on I2C1 pins, CAN 2 on TMR01 pins"
-config XENO_DRIVERS_RTCAN_MSCAN_PSC2
+config XENO_DRIVERS_RTCAN_MSCAN_PSC2
bool "CAN 1 and 2 on PSC2 pins"
endchoice
Index: ksrc/drivers/can/mscan/rtcan_mscan.c
===================================================================
--- ksrc/drivers/can/mscan/rtcan_mscan.c (revision 1834)
+++ ksrc/drivers/can/mscan/rtcan_mscan.c (working copy)
@@ -251,6 +251,21 @@
regs->cantier = 0;
/* Wake up a sender */
rtdm_sem_up(&dev->tx_sem);
+
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ if (dev->tx_socket) {
+ memcpy((void *)&dev->tx_skb.rb_frame + dev->tx_skb.rb_frame_size,
+ ×tamp, TIMESTAMP_SIZE);
+
+ if (recv_lock_free) {
+ recv_lock_free = 0;
+ rtdm_lock_get(&rtcan_recv_list_lock);
+ rtdm_lock_get(&rtcan_socket_lock);
+ }
+
+ rtcan_tx_loopback(dev);
+ }
+#endif /* CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK */
}
/* Wakeup interrupt? */
Index: ksrc/drivers/can/rtcan_socket.h
===================================================================
--- ksrc/drivers/can/rtcan_socket.h (revision 1834)
+++ ksrc/drivers/can/rtcan_socket.h (working copy)
@@ -167,6 +167,10 @@
uint32_t rx_buf_full;
struct rtcan_filter_list *flist;
+
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ int tx_loopback;
+#endif
};
Index: ksrc/drivers/can/rtcan_raw.h
===================================================================
--- ksrc/drivers/can/rtcan_raw.h (revision 1834)
+++ ksrc/drivers/can/rtcan_raw.h (working copy)
@@ -32,6 +32,10 @@
void rtcan_rcv(struct rtcan_device *rtcandev, struct rtcan_skb *skb);
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+void rtcan_tx_loopback(struct rtcan_device *rtcandev);
+#endif /* CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK */
+
#ifdef CONFIG_PROC_FS
int __init rtcan_raw_proto_register(void);
void __exit rtcan_raw_proto_unregister(void);
Index: ksrc/drivers/can/Config.in
===================================================================
--- ksrc/drivers/can/Config.in (revision 1834)
+++ ksrc/drivers/can/Config.in (working copy)
@@ -9,6 +9,7 @@
if [ "$CONFIG_XENO_DRIVERS_RTCAN" != "n" ]; then
bool 'Enable debug output' CONFIG_XENO_DRIVERS_RTCAN_DEBUG
+ bool 'Enable TX loopback to local sockets' CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
int 'Size of receive ring buffers (must be 2^N)' CONFIG_XENO_DRIVERS_RTCAN_RXBUF_SIZE 1024
int 'Maximum number of devices' CONFIG_XENO_DRIVERS_RTCAN_MAX_DEVICES 4
int 'Maximum number of receive filters per device' CONFIG_XENO_DRIVERS_RTCAN_MAX_RECEIVERS 16
Index: ksrc/drivers/can/sja1000/Kconfig
===================================================================
--- ksrc/drivers/can/sja1000/Kconfig (revision 1834)
+++ ksrc/drivers/can/sja1000/Kconfig (working copy)
@@ -5,7 +5,12 @@
config XENO_DRIVERS_RTCAN_SJA1000_ISA
depends on XENO_DRIVERS_RTCAN_SJA1000
tristate "Standard ISA controllers"
+ help
+ This driver is for CAN devices connected to the ISA bus of a PC
+ or a PC/104 system. The I/O port, interrupt number and a few other
+ hardware specific parameters can be defined via module parameters.
+
config XENO_DRIVERS_RTCAN_SJA1000_ISA_MAX_DEV
depends on XENO_DRIVERS_RTCAN_SJA1000_ISA
int "Maximum number of controllers"
@@ -14,7 +19,12 @@
config XENO_DRIVERS_RTCAN_SJA1000_MEM
depends on XENO_DRIVERS_RTCAN_SJA1000
tristate "Memory mapped controllers"
+ help
+ This driver is for memory mapped CAN devices. The memory address,
+ interrupt number and a few other hardware specific parameters can
+ be defined via module parameters.
+
config XENO_DRIVERS_RTCAN_SJA1000_MEM_MAX_DEV
depends on XENO_DRIVERS_RTCAN_SJA1000_MEM
int "Maximum number of controllers"
@@ -23,7 +33,20 @@
config XENO_DRIVERS_RTCAN_SJA1000_PEAK_PCI
depends on XENO_DRIVERS_RTCAN_SJA1000
tristate "PEAK PCI Card"
+ help
+ This driver is for the PCAN PCI, the PC-PCI CAN plug-in card (1 or
+ 2 channel) from PEAK Systems (http://www.peak-system.com). To get
+ the second channel working, Xenomai's shared interrupt support
+ must be enabled.
+
config XENO_DRIVERS_RTCAN_SJA1000_PEAK_DNG
depends on XENO_DRIVERS_RTCAN_SJA1000
tristate "PEAK Parallel Port Dongle"
+ help
+
+ This driver is for the PCAN Dongle, the PC parallel port to CAN
+ converter from PEAK Systems (http://www.peak-system.com). You need
+ to disable parallel port support in the kernel (CONFIG_PARPORT) for
+ proper operation. The interface type (SP or EPP), I/O port and
+ interrupt number should be defined via module parameters.
\ No newline at end of file
Index: ksrc/drivers/can/sja1000/rtcan_sja1000.c
===================================================================
--- ksrc/drivers/can/sja1000/rtcan_sja1000.c (revision 1834)
+++ ksrc/drivers/can/sja1000/rtcan_sja1000.c (working copy)
@@ -312,11 +312,27 @@
}
/* Transmit Interrupt? */
- if (irq_source & SJA_IR_TI)
+ if (irq_source & SJA_IR_TI) {
/* Wake up a sender */
rtdm_sem_up(&dev->tx_sem);
+#ifdef CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK
+ if (dev->tx_socket) {
+ /* Copy timestamp to skb */
+ memcpy((void *)&dev->tx_skb.rb_frame + dev->tx_skb.rb_frame_size,
+ ×tamp, TIMESTAMP_SIZE);
+ if (recv_lock_free) {
+ recv_lock_free = 0;
+ rtdm_lock_get(&rtcan_recv_list_lock);
+ rtdm_lock_get(&rtcan_socket_lock);
+ }
+
+ rtcan_tx_loopback(dev);
+ }
+#endif /* CONFIG_XENO_DRIVERS_RTCAN_TX_LOOPBACK */
+ }
+
/* Receive Interrupt? */
if (irq_source & SJA_IR_RI) {
_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core