Hi All,
Here is the RTEMS CAN driver framework I've been talking about. Please
give me feedback, and don't worry about being harsh. I want to commit
something of value.
Concerns
========
* Usage of return codes.
* General higher level error handling.
* Changing can bit rate.
* In general, changing CAN parameters at runtime.
* Task model: Should there really be an RX and TX task required by the
RTEMS driver? Is the method of starting and stopping tasks acceptable?
The motivation for this is that the CAN controller we are using, (STM32
BxCAN) requires you to re-initialize the device to change parameters.
This is a bit awkward with first calling open, and then IOCTL to
configure the bus. Any thoughts?
Thanks,
Isaac
P.S. I'm having trouble with git send-email. Something is not quite
right with our mail server here. I've attached the patch instead.
--
Isaac Gutekunst
Embedded Systems Software Engineer
isaac.guteku...@vecna.com
www.vecna.com
>From a151795883f68dbff91d3044bbf8d629b4b6996f Mon Sep 17 00:00:00 2001
From: Isaac Gutekunst <isaac.guteku...@vecna.com>
Date: Mon, 24 Aug 2015 09:45:27 -0400
Subject: [PATCH] cpukit: Create CAN Driver framework
---
cpukit/dev/Makefile.am | 6 +
cpukit/dev/can/can.c | 510 ++++++++++++++++++++++++++++++
cpukit/dev/include/dev/can/can-internal.h | 208 ++++++++++++
cpukit/dev/include/dev/can/can.h | 86 +++++
cpukit/dev/preinstall.am | 13 +
cpukit/score/cpu/arm/rtems/score/cpu.h | 2 +-
6 files changed, 824 insertions(+), 1 deletion(-)
create mode 100644 cpukit/dev/can/can.c
create mode 100644 cpukit/dev/include/dev/can/can-internal.h
create mode 100644 cpukit/dev/include/dev/can/can.h
diff --git a/cpukit/dev/Makefile.am b/cpukit/dev/Makefile.am
index 47a1585..cffcf25 100644
--- a/cpukit/dev/Makefile.am
+++ b/cpukit/dev/Makefile.am
@@ -11,6 +11,11 @@ include_dev_i2c_HEADERS += include/dev/i2c/gpio-nxp-pca9535.h
include_dev_i2c_HEADERS += include/dev/i2c/i2c.h
include_dev_i2c_HEADERS += include/dev/i2c/switch-nxp-pca9548a.h
+include_dev_candir = $(includedir)/dev/can
+include_dev_can_HEADERS =
+include_dev_can_HEADERS += include/dev/can/can.h
+include_dev_can_HEADERS += include/dev/can/can-internal.h
+
include_linuxdir = $(includedir)/linux
include_linux_HEADERS =
include_linux_HEADERS += include/linux/i2c.h
@@ -24,6 +29,7 @@ libdev_a_SOURCES += i2c/gpio-nxp-pca9535.c
libdev_a_SOURCES += i2c/i2c-bus.c
libdev_a_SOURCES += i2c/i2c-dev.c
libdev_a_SOURCES += i2c/switch-nxp-pca9548a.c
+libdev_a_SOURCES += can/can.c
include $(srcdir)/preinstall.am
include $(top_srcdir)/automake/local.am
diff --git a/cpukit/dev/can/can.c b/cpukit/dev/can/can.c
new file mode 100644
index 0000000..2610498
--- /dev/null
+++ b/cpukit/dev/can/can.c
@@ -0,0 +1,510 @@
+/**
+ * @file can.c
+ *
+ * @ingroup can
+ * @brief Control Area Network (can) Driver API
+ *
+ * @brief RTEMS can driver. Exposes a posix interface to the can bus
+ * similar to lincan.
+ *
+ */
+
+/*
+ * Copyright (c) 2015 Vecna Technologies, Inc.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <dev/can/can-internal.h>
+
+
+#include <rtems/imfs.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <fcntl.h>
+
+#define CAN_QUEUE_LEN 10
+#define CAN_TASK_PRIORITY 70
+
+static bool free_busses[10] = {true};
+
+int get_free_bus_number(
+ void
+)
+{
+ int i;
+ for (i = 1; i < 10; i++) {
+ if (true == free_busses[i]) {
+ free_busses[i] = false;
+ return i;
+ }
+ }
+ return -1;
+}
+
+void can_bus_obtain(can_bus *bus)
+{
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_obtain(bus->mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+ (void) sc;
+}
+
+void can_bus_release(can_bus *bus)
+{
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_release(bus->mutex);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+ (void) sc;
+}
+
+int can_bus_change_baudrate(
+ can_bus * bus,
+ uint32_t baud
+)
+{
+ can_bus_obtain(bus);
+ bus->de_init(bus);
+ bus->init(bus, baud);
+ can_bus_release(bus);
+ return 0;
+}
+
+int can_bus_set_filter(
+ can_bus * bus,
+ can_filter * filter
+)
+{
+ int err;
+ _Assert(filter);
+ can_bus_obtain(bus);
+ err = bus->set_filter(bus, filter);
+ can_bus_release(bus);
+ return err;
+}
+
+
+int can_bus_init_default(
+ can_bus * bus,
+ long baud
+)
+{
+ (void) bus;
+ (void) baud;
+ return 0;
+ return -EIO;
+}
+
+int can_bus_de_init_default(
+ can_bus * bus
+)
+{
+ (void) bus;
+ return -EIO;
+}
+
+int can_bus_set_filter_default(
+ can_bus * bus,
+ can_filter * filter
+)
+{
+ (void) bus;
+ (void) filter;
+ return -EIO;
+}
+int can_bus_get_num_filters_default(
+ can_bus * bus
+)
+{
+ (void) bus;
+ return -EIO;
+}
+
+int can_bus_transfer(can_bus *bus, can_msg *msgs, uint32_t msg_count)
+{
+ int err;
+
+ _Assert(msg_count > 0);
+
+ // error checking
+
+ can_bus_obtain(bus);
+ can_bus_release(bus);
+
+ return err;
+}
+
+static ssize_t can_bus_read(
+ rtems_libio_t *iop,
+ void *buffer,
+ size_t count
+)
+{
+ can_bus *bus = IMFS_generic_get_context_by_iop(iop);
+ int err;
+ rtems_status_code sc;
+ can_msg msg;
+ size_t len;
+
+
+ if (count != sizeof(msg)) {
+ return 0;
+ }
+
+ rtems_option wait_options;
+ if (bus->oflag & O_NONBLOCK) {
+ wait_options = RTEMS_NO_WAIT;
+ } else {
+ wait_options = RTEMS_WAIT;
+ }
+ sc = rtems_message_queue_receive(bus->rx_msg_queue,
+ &msg,
+ &len,
+ wait_options,
+ RTEMS_NO_TIMEOUT);
+
+ if (RTEMS_SUCCESSFUL != sc) {
+ return 0;
+ }
+
+ _Assert(len == sizeof(msg));
+ memcpy(buffer, &msg, sizeof(msg));
+ return sizeof(msg);
+
+ if (err == 0) {
+ return 0;
+ } else {
+ rtems_set_errno_and_return_minus_one(-err);
+ }
+}
+
+static ssize_t can_bus_write(
+ rtems_libio_t *iop,
+ const void *buffer,
+ size_t count
+)
+{
+ can_bus *bus = IMFS_generic_get_context_by_iop(iop);
+ int err = 0;
+ rtems_status_code sc;
+
+ can_msg * msg = (can_msg * ) buffer;
+
+ _Assert(count % sizeof(can_msg) == 0);
+ _Assert(msg->len <= 8);
+
+ size_t msg_count = count / sizeof(can_msg);
+ int i;
+ for (i = 0; i < msg_count; i++) {
+ sc = rtems_message_queue_send(bus->tx_msg_queue,
+ buffer + sizeof(can_msg) * i,
+ sizeof(can_msg));
+ }
+
+ if (RTEMS_SUCCESSFUL != sc) {
+ err = EIO;
+ }
+
+ if (err == 0) {
+ return 0;
+ } else {
+ rtems_set_errno_and_return_minus_one(-err);
+ }
+}
+
+static int can_bus_close(
+ rtems_libio_t *iop
+)
+{
+ can_bus *bus = IMFS_generic_get_context_by_iop(iop);
+ int err;
+ can_bus_obtain(bus);
+ err = bus->de_init(bus);
+ can_bus_release(bus);
+ if (err == 0) {
+ return 0;
+ } else {
+ rtems_set_errno_and_return_minus_one(-err);
+ }
+}
+
+static int can_bus_open(
+ rtems_libio_t *iop,
+ const char *path,
+ int oflag,
+ mode_t mode
+)
+{
+ rtems_status_code sc;
+ can_bus *bus = IMFS_generic_get_context_by_iop(iop);
+ int err;
+ can_bus_obtain(bus);
+ err = bus->init(bus, bus->default_baud);
+ bus->oflag = oflag;
+ can_bus_release(bus);
+
+ sc = rtems_task_start(
+ bus->rx_task_id,
+ bus->rx_task,
+ (rtems_task_argument) bus
+ );
+ if (err == 0) {
+ return 0;
+ } else {
+ rtems_set_errno_and_return_minus_one(-err);
+ }
+}
+
+static int can_bus_ioctl(
+ rtems_libio_t *iop,
+ ioctl_command_t command,
+ void *arg
+)
+{
+ can_bus *bus = IMFS_generic_get_context_by_iop(iop);
+ can_filter * filter;
+ int err;
+
+ switch (command) {
+ case CAN_SET_FILTER:
+ filter = (can_filter*) arg;
+ bus->set_filter(bus, filter);
+ break;
+
+ case CAN_GET_NUM_FILTERS:
+ return bus->get_num_filters(bus);
+ break;
+
+ default:
+ err = -ENOTTY;
+ break;
+ }
+
+ if (err == 0) {
+ return 0;
+ } else {
+ rtems_set_errno_and_return_minus_one(-err);
+ }
+}
+
+static const rtems_filesystem_file_handlers_r can_bus_handler = {
+ .open_h = can_bus_open,
+ .close_h = can_bus_close,
+ .read_h = can_bus_read,
+ .write_h = can_bus_write,
+ .ioctl_h = can_bus_ioctl,
+ .lseek_h = rtems_filesystem_default_lseek,
+ .fstat_h = IMFS_stat,
+ .ftruncate_h = rtems_filesystem_default_ftruncate,
+ .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fcntl_h = rtems_filesystem_default_fcntl,
+ .kqfilter_h = rtems_filesystem_default_kqfilter,
+ .poll_h = rtems_filesystem_default_poll,
+ .readv_h = rtems_filesystem_default_readv,
+ .writev_h = rtems_filesystem_default_writev
+};
+
+static void can_bus_node_destroy(IMFS_jnode_t *node)
+{
+ can_bus *bus;
+
+ bus = IMFS_generic_get_context_by_node(node);
+ (*bus->destroy)(bus);
+
+ IMFS_node_destroy_default(node);
+}
+
+static const IMFS_node_control can_bus_node_control = IMFS_GENERIC_INITIALIZER(
+ &can_bus_handler,
+ IMFS_node_initialize_generic,
+ can_bus_node_destroy
+);
+
+int can_bus_register(
+ can_bus *bus
+)
+{
+ int rv;
+ rtems_status_code sc;
+ char bus_path[12];
+ int bus_number = get_free_bus_number();
+ if (bus_number > 0) {
+ sprintf(bus_path, "/dev/can%d", bus_number);
+ } else {
+ return -1;
+ }
+
+ bus->bus_number = bus_number;
+
+ rv = IMFS_make_generic_node(
+ bus_path,
+ S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
+ &can_bus_node_control,
+ bus
+ );
+ if (rv != 0) {
+ (*bus->destroy)(bus);
+ }
+
+ sc = rtems_semaphore_create(
+ rtems_build_name('C', '0' + bus->bus_number, 'M', 'X'),
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
+ 0,
+ &bus->mutex
+ );
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ (*bus->destroy)(bus);
+ rtems_set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ sc = rtems_message_queue_create(
+ rtems_build_name('C', '0' + bus->bus_number, 'R', 'Q'),
+ CAN_QUEUE_LEN,
+ sizeof(can_msg),
+ RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
+ &bus->rx_msg_queue
+ );
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ (*bus->destroy)(bus);
+ rtems_set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ sc = rtems_message_queue_create(
+ rtems_build_name('C', '0' + bus->bus_number, 'T', 'Q'),
+ CAN_QUEUE_LEN,
+ sizeof(can_msg),
+ RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
+ &bus->tx_msg_queue
+ );
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ (*bus->destroy)(bus);
+ rtems_set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ sc = rtems_task_create(
+ rtems_build_name('C', '0' + bus->bus_number, 'R', 'X'),
+ CAN_TASK_PRIORITY - 1,
+ RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_PREEMPT,
+ RTEMS_NO_FLOATING_POINT,
+ &bus->rx_task_id
+ );
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ (*bus->destroy)(bus);
+ rtems_set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ sc = rtems_task_create(
+ rtems_build_name('C', '0' + bus->bus_number, 'T', 'X'),
+ CAN_TASK_PRIORITY,
+ RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_PREEMPT,
+ RTEMS_NO_FLOATING_POINT,
+ &bus->tx_task_id
+ );
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ (*bus->destroy)(bus);
+ rtems_set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ return rv;
+}
+
+static int can_bus_do_init(
+ can_bus *bus,
+ void (*destroy)(can_bus *bus)
+)
+{
+
+ bus->destroy = destroy;
+ bus->set_filter = can_bus_set_filter_default;
+ bus->init = can_bus_init_default;
+ bus->de_init = can_bus_de_init_default;
+ bus->set_filter = can_bus_set_filter_default;
+ bus->get_num_filters = can_bus_get_num_filters_default;
+ return 0;
+}
+
+void can_bus_destroy(can_bus *bus)
+{
+ rtems_status_code sc;
+
+ bus->de_init(bus);
+
+ sc = rtems_semaphore_delete(bus->mutex);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_message_queue_delete(bus->rx_msg_queue);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_message_queue_delete(bus->tx_msg_queue);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_task_delete(bus->rx_task_id);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_task_delete(bus->tx_task_id);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+
+ (void) sc;
+}
+
+
+void can_bus_destroy_and_free(can_bus *bus)
+{
+ can_bus_destroy(bus);
+ free(bus);
+}
+
+
+int can_bus_init(can_bus *bus)
+{
+ memset(bus, 0, sizeof(*bus));
+
+ int err = can_bus_do_init(bus, can_bus_destroy);
+
+ return err;
+}
+
+
+can_bus *can_bus_alloc_and_init(size_t size)
+{
+ can_bus *bus = NULL;
+
+ if (size >= sizeof(*bus)) {
+ bus = calloc(1, size);
+ if (bus != NULL) {
+ int rv;
+
+ bus->default_baud = 1000000;
+ rv = can_bus_do_init(bus, can_bus_destroy_and_free);
+ if (rv != 0) {
+ return NULL;
+ }
+ }
+ }
+
+ return bus;
+}
+
+uint32_t can_filter_stdid(uint32_t id) {
+ return id << 21;
+}
diff --git a/cpukit/dev/include/dev/can/can-internal.h b/cpukit/dev/include/dev/can/can-internal.h
new file mode 100644
index 0000000..5fa4e2d
--- /dev/null
+++ b/cpukit/dev/include/dev/can/can-internal.h
@@ -0,0 +1,208 @@
+/**
+ * @file can.h
+ *
+ * @brief Control Area Network (can) Driver API
+ *
+ * @ingroup can
+ */
+
+/*
+ * Copyright (c) 2015 Vecna Technologies, Inc.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+
+#ifndef _DEV_CAN_INTERNAL_H
+#define _DEV_CAN_INTERNAL_H
+
+#include <rtems.h>
+#include <rtems/seterr.h>
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <dev/can/can.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct can_bus can_bus;
+
+typedef struct can_rdwr_ioctl_data can_rdwr_ioctl_data;
+
+
+/**
+ * @brief Default can bus clock in Hz.
+ */
+#define CAN_BUS_CLOCK_DEFAULT 100000
+
+/**
+ * @brief can bus control.
+ */
+struct can_bus {
+
+ int bus_number;
+
+ int oflag;
+
+ int (*init)(can_bus * bus, long buad);
+
+ int (*de_init)(can_bus * bus);
+
+ /*
+ * @brief Destroys the bus.
+ *
+ * @param[in] bus The bus control.
+ */
+ void (*destroy)(can_bus *bus);
+
+ /*
+ * @brief install/set a can_filter
+ *
+ * @param[in] can_bus bus instance
+ * @param[in] can_filter filter. The filter to be installed or updated.
+ * There is no mechanism for disabling filters. Filters
+ * should be disabled by setting the mask to all zeros
+ *
+ */
+ int (*set_filter) (can_bus * bus, can_filter * filter);
+
+
+ /*
+ * @brief Get the number of supported hardware filters
+ *
+ * @param[in] can_bus bus instance
+ * @return number of supported filters
+ */
+ int (*get_num_filters) (can_bus * bus);
+
+ /**
+ * Task for handling TX responsibilities
+ */
+ rtems_id tx_task_id;
+
+ /**
+ * Task for handling RX responsibilities
+ */
+ rtems_id rx_task_id;
+
+ /**
+ * TX task function entry point
+ */
+ rtems_task_entry rx_task;
+
+ /**
+ * RX task function entry point
+ */
+ rtems_task_entry tx_task;
+
+ /**
+ * Queues for passing messages
+ * to and from CAN driver and
+ * low level driver
+ */
+ rtems_id rx_msg_queue;
+ rtems_id tx_msg_queue;
+
+ can_filter default_filter;
+ long default_baud;
+
+
+ long baud;
+
+ /**
+ * @brief Mutex to protect the bus access.
+ */
+ rtems_id mutex;
+};
+
+/**
+ * @brief Initializes a bus control.
+ *
+ * After a sucessful initialization the bus control must be destroyed via
+ * can_bus_destroy(). A registered bus control will be automatically destroyed
+ * in case the device file is unlinked. Make sure to call can_bus_destroy() in
+ * a custom destruction handler.
+ *
+ * @param[in] bus The bus control.
+ *
+ * @retval 0 Successful operation.
+ * @retval -1 An error occurred. The errno is set to indicate the error.
+ *
+ * @see can_bus_register()
+ */
+int can_bus_init(can_bus *bus);
+
+/**
+ * @brief Allocates a bus control from the heap and initializes it.
+ *
+ * After a sucessful allocation and initialization the bus control must be
+ * destroyed via can_bus_destroy_and_free(). A registered bus control will be
+ * automatically destroyed in case the device file is unlinked. Make sure to
+ * call can_bus_destroy_and_free() in a custom destruction handler.
+ *
+ * @param[in] size The size of the bus control. This enables the addition of
+ * bus controller specific data to the base bus control. The bus control is
+ * zero initialized.
+ *
+ * @retval non-NULL The new bus control.
+ * @retval NULL An error occurred. The errno is set to indicate the error.
+ *
+ * @see can_bus_register()
+ */
+can_bus *can_bus_alloc_and_init(size_t size);
+
+/**
+ * @brief Destroys a bus control.
+ *
+ * @param[in] bus The bus control.
+ */
+void can_bus_destroy(can_bus *bus);
+
+/**
+ * @brief Destroys a bus control and frees its memory.
+ *
+ * @param[in] bus The bus control.
+ */
+void can_bus_destroy_and_free(can_bus *bus);
+
+/**
+ * @brief Registers a bus control.
+ *
+ * This function claims ownership of the bus control regardless if the
+ * registration is successful or not.
+ *
+ * @param[in] bus The bus control.
+ * @param[in] bus_path The path to the bus device file.
+ *
+ * @retval 0 Successful operation.
+ * @retval -1 An error occurred. The errno is set to indicate the error.
+ */
+int can_bus_register(
+ can_bus *bus
+);
+
+/**
+ * @brief Obtains the bus.
+ *
+ * @param[in] bus The bus control.
+ */
+void can_bus_obtain(can_bus *bus);
+
+/**
+ * @brief Releases the bus.
+ *
+ * @param[in] bus The bus control.
+ */
+void can_bus_release(can_bus *bus);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _DEV_can_internal_H */
diff --git a/cpukit/dev/include/dev/can/can.h b/cpukit/dev/include/dev/can/can.h
new file mode 100644
index 0000000..fc16957
--- /dev/null
+++ b/cpukit/dev/include/dev/can/can.h
@@ -0,0 +1,86 @@
+/**
+ * @file can.h
+ *
+ * @brief Control Area Network (can) Driver API
+ *
+ * @ingroup can
+ */
+
+/*
+ * Copyright (c) 2015 Vecna Technologies, Inc.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+
+#ifndef _DEV_CAN_H
+#define _DEV_CAN_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define MAX_CAN_MSG_LEN 8
+
+typedef struct {
+ uint32_t id;
+ uint8_t len;
+ uint8_t data[MAX_CAN_MSG_LEN];
+} can_msg;
+
+struct can_filter{
+ /**
+ * Filter number in can
+ * hardware
+ */
+ uint16_t number;
+
+ /**
+ * 32 bit mask.
+ *
+ * Use can_filter_stdid to create
+ * a mask for an 11 bit ID/mask.
+ */
+ uint32_t mask;
+
+ /**
+ * 32 bit filter.
+ *
+ * Use can_filter_stdid to create
+ * a filter for an 11 bit id
+ */
+ uint32_t filter;
+};
+
+typedef struct can_filter can_filter;
+
+
+/**
+ * IOCTL Commands
+ */
+#define IOCTL_CAN_TYPE 72
+
+#define CAN_SET_BAUDRATE _IOW(IOCTL_CAN_TYPE, 1, unsigned long)
+#define CAN_GET_NUM_FILTERS _IOR(IOCTL_CAN_TYPE, 2, void )
+#define CAN_SET_FILTER _IOW(IOCTL_CAN_TYPE, 3, can_filter)
+
+/**
+ * @brief Create an mask/filter for an 11
+ * bit CAN id.
+ *
+ * @param[in] 11 bit CAN id
+ * @return 32 bit filter for use in a
+ * can_filter struct.
+ */
+uint32_t can_filter_stdid(uint32_t id);
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _DEV_can_can_H */
diff --git a/cpukit/dev/preinstall.am b/cpukit/dev/preinstall.am
index f73107b..02bbdb5 100644
--- a/cpukit/dev/preinstall.am
+++ b/cpukit/dev/preinstall.am
@@ -39,6 +39,19 @@ $(PROJECT_INCLUDE)/dev/i2c/switch-nxp-pca9548a.h: include/dev/i2c/switch-nxp-pca
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dev/i2c/switch-nxp-pca9548a.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/dev/i2c/switch-nxp-pca9548a.h
+$(PROJECT_INCLUDE)/dev/can/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/dev/can
+ @: > $(PROJECT_INCLUDE)/dev/can/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/dev/can/$(dirstamp)
+
+$(PROJECT_INCLUDE)/dev/can/can.h: include/dev/can/can.h $(PROJECT_INCLUDE)/dev/can/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dev/can/can.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/dev/can/can.h
+
+$(PROJECT_INCLUDE)/dev/can/can-internal.h: include/dev/can/can-internal.h $(PROJECT_INCLUDE)/dev/can/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dev/can/can-internal.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/dev/can/can-internal.h
+
$(PROJECT_INCLUDE)/linux/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/linux
@: > $(PROJECT_INCLUDE)/linux/$(dirstamp)
diff --git a/cpukit/score/cpu/arm/rtems/score/cpu.h b/cpukit/score/cpu/arm/rtems/score/cpu.h
index 6aced79..b7a9dfe 100644
--- a/cpukit/score/cpu/arm/rtems/score/cpu.h
+++ b/cpukit/score/cpu/arm/rtems/score/cpu.h
@@ -171,7 +171,7 @@
#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
-#define CPU_STACK_MINIMUM_SIZE (1024 * 4)
+#define CPU_STACK_MINIMUM_SIZE (1024 * 2)
/* AAPCS, section 4.1, Fundamental Data Types */
#define CPU_SIZEOF_POINTER 4
--
1.9.1
_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel