[PATCH] cpukit: New SPI framework implemented #2776
Gedare Bloom
gedare at rtems.org
Mon Sep 12 13:49:46 UTC 2016
Good. We'll need some user-friendly (BSP developer) documentation eventually.
On Mon, Sep 12, 2016 at 9:10 AM, Alexander Krutwig
<alexander.krutwig at embedded-brains.de> wrote:
> Linux Userspace API was taken as a template
> Test libtests/spi01 is included into testsuite
> ---
> cpukit/dev/Makefile.am | 10 +
> cpukit/dev/include/dev/spi/spi.h | 452 +++++++++++++++++++++++++++++
> cpukit/dev/include/linux/spi/spidev.h | 242 +++++++++++++++
> cpukit/dev/spi/spi-bus.c | 362 +++++++++++++++++++++++
> cpukit/dev/spi/spi-dev.c | 291 +++++++++++++++++++
> testsuites/libtests/Makefile.am | 1 +
> testsuites/libtests/spi01/buffer_test_io.h | 219 ++++++++++++++
> testsuites/libtests/spi01/init.c | 256 ++++++++++++++++
> testsuites/libtests/spi01/spi01.doc | 11 +
> testsuites/libtests/spi01/spi01.scn | 2 +
> testsuites/libtests/spi01/tmacros.h | 372 ++++++++++++++++++++++++
> 11 files changed, 2218 insertions(+)
> create mode 100644 cpukit/dev/include/dev/spi/spi.h
> create mode 100644 cpukit/dev/include/linux/spi/spidev.h
> create mode 100644 cpukit/dev/spi/spi-bus.c
> create mode 100644 cpukit/dev/spi/spi-dev.c
> create mode 100644 testsuites/libtests/spi01/buffer_test_io.h
> create mode 100644 testsuites/libtests/spi01/init.c
> create mode 100644 testsuites/libtests/spi01/spi01.doc
> create mode 100644 testsuites/libtests/spi01/spi01.scn
> create mode 100644 testsuites/libtests/spi01/tmacros.h
>
> diff --git a/cpukit/dev/Makefile.am b/cpukit/dev/Makefile.am
> index 47a1585..3d39e38 100644
> --- a/cpukit/dev/Makefile.am
> +++ b/cpukit/dev/Makefile.am
> @@ -11,11 +11,19 @@ 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_spidir = $(includedir)/dev/spi
> +include_dev_spi_HEADERS =
> +include_dev_spi_HEADERS += include/dev/spi/spi.h
> +
> include_linuxdir = $(includedir)/linux
> include_linux_HEADERS =
> include_linux_HEADERS += include/linux/i2c.h
> include_linux_HEADERS += include/linux/i2c-dev.h
>
> +include_linux_spidir = $(includedir)/linux/spi
> +include_linux_spi_HEADERS =
> +include_linux_spi_HEADERS += include/linux/spi/spidev.h
> +
> noinst_LIBRARIES = libdev.a
>
> libdev_a_SOURCES =
> @@ -24,6 +32,8 @@ 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 += spi/spi-dev.c
> +libdev_a_SOURCES += spi/spi-bus.c
>
> include $(srcdir)/preinstall.am
> include $(top_srcdir)/automake/local.am
> diff --git a/cpukit/dev/include/dev/spi/spi.h b/cpukit/dev/include/dev/spi/spi.h
> new file mode 100644
> index 0000000..ce3fd7c
> --- /dev/null
> +++ b/cpukit/dev/include/dev/spi/spi.h
> @@ -0,0 +1,452 @@
> +/**
> + * @file
> + *
> + * @brief Inter-Integrated Circuit (SPI) Driver API
> + *
> + * @ingroup SPI
> + */
> +
> +/*
> + * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at embedded-brains.de>
> + *
> + * 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.
> + */
> +
> +#ifndef _DEV_SPI_SPI_H
> +#define _DEV_SPI_SPI_H
> +
> +#include <linux/spi/spidev.h>
> +
> +#include <rtems.h>
> +#include <rtems/seterr.h>
> +
> +#include <sys/ioctl.h>
> +#include <sys/stat.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +typedef struct spi_ioc_transfer spi_ioc_transfer;
> +
> +typedef struct spi_bus spi_bus;
> +
> +typedef struct spi_dev spi_dev;
> +
> +typedef struct spi_rdwr_ioctl_data spi_rdwr_ioctl_data;
> +
> +/**
> + * @defgroup SPI Inter-Integrated Circuit (SPI) Driver
> + *
> + * @brief Inter-Integrated Circuit (SPI) bus and device driver support.
> + *
> + * @{
> + */
> +
> +/**
> + * @defgroup SPIBus SPI Bus Driver
> + *
> + * @ingroup SPI
> + *
> + * @{
> + */
> +
> +/**
> + * @name SPI IO Control Commands
> + *
> + * @{
> + */
> +
> +/**
> + * @brief Obtains the bus.
> + *
> + * This command has no argument.
> + */
> +#define SPI_BUS_OBTAIN 0x800
> +
> +/**
> + * @brief Releases the bus.
> + *
> + * This command has no argument.
> + */
> +#define SPI_BUS_RELEASE 0x801
> +
> +/**
> + * @brief Gets the bus control.
> + *
> + * The argument type is a pointer to spi_bus pointer.
> + */
> +#define SPI_BUS_GET_CONTROL 0x802
> +
> +/**
> + * @brief Sets the bus clock in Hz.
> + *
> + * The argument type is unsigned long.
> + */
> +#define SPI_BUS_SET_CLOCK 0x803
> +
> +/** @} */
> +
> +/**
> + * @brief Default SPI bus clock in Hz.
> + */
> +#define SPI_BUS_CLOCK_DEFAULT 100000
> +
> +/**
> + * @brief Data Field of the SPI bus control
> + */
> +typedef struct {
> + /**
> + * @brief Current mode.
> + */
> + uint32_t mode;
> +
> + /**
> + * @brief Indicates the bits per word used on the device.
> + */
> + uint8_t bits_per_word;
> +
> + /**
> + * @brief Indicates the speed of the current device message.
> + */
> + uint32_t speed_hz;
> +
> + /**
> + * @brief Indicates the delay between transfers on different chip select
> + * devices.
> + */
> + uint16_t delay_usecs;
> +
> + /**
> + * @brief Indicates which device is selected by chip select
> + */
> + uint8_t cs;
> +} spi_bus_data;
> +
> +/**
> + * @brief SPI bus control.
> + */
> +struct spi_bus {
> + /**
> + * @brief Transfers SPI messages.
> + *
> + * @param[in] bus The bus control.
> + * @param[in] msgs The messages to transfer.
> + * @param[in] msg_count The count of messages to transfer. It must be
> + * positive.
> + *
> + * @retval 0 Successful operation.
> + * @retval negative Negative error number in case of an error.
> + */
> + int (*transfer)(spi_bus *bus, spi_ioc_transfer *msgs, uint32_t msg_count);
> +
> + /**
> + * @brief Sets the bus clock.
> + *
> + * @param[in] bus The bus control.
> + * @param[in] clock The desired bus clock in Hz.
> + *
> + * @retval 0 Successful operation.
> + * @retval negative Negative error number in case of an error.
> + */
> + int (*set_clock)(spi_bus *bus, unsigned long clock);
> +
> + /**
> + * @brief Destroys the bus.
> + *
> + * @param[in] bus The bus control.
> + */
> + void (*destroy)(spi_bus *bus);
> +
> + /**
> + * @brief Mutex to protect the bus access.
> + */
> + rtems_id mutex;
> +
> + /**
> + * @brief Maximum Speed in Hz
> + */
> + uint32_t max_speed;
> +
> + /**
> + * @brief Indicates if LSB is supposed to be transmitted first.
> + */
> + uint8_t lsb_first;
> +
> + /**
> + * @brief Indicates if chip select must be set high after transfer.
> + */
> + uint8_t cs_change;
> +
> + /**
> + * @brief Data field of the bus control.
> + */
> + spi_bus_data data;
> +};
> +
> +/**
> + * @brief Initializes a bus control.
> + *
> + * After a sucessful initialization the bus control must be destroyed via
> + * spi_bus_destroy(). A registered bus control will be automatically destroyed
> + * in case the device file is unlinked. Make sure to call spi_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 spi_bus_register()
> + */
> +int spi_bus_init(spi_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 spi_bus_destroy_and_free(). A registered bus control will be
> + * automatically destroyed in case the device file is unlinked. Make sure to
> + * call spi_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 spi_bus_register()
> + */
> +spi_bus *spi_bus_alloc_and_init(size_t size);
> +
> +/**
> + * @brief Destroys a bus control.
> + *
> + * @param[in] bus The bus control.
> + */
> +void spi_bus_destroy(spi_bus *bus);
> +
> +/**
> + * @brief Destroys a bus control and frees its memory.
> + *
> + * @param[in] bus The bus control.
> + */
> +void spi_bus_destroy_and_free(spi_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 spi_bus_register(
> + spi_bus *bus,
> + const char *bus_path
> +);
> +
> +/**
> + * @brief Obtains the bus.
> + *
> + * @param[in] bus The bus control.
> + */
> +void spi_bus_obtain(spi_bus *bus);
> +
> +/**
> + * @brief Releases the bus.
> + *
> + * @param[in] bus The bus control.
> + */
> +void spi_bus_release(spi_bus *bus);
> +
> +/**
> + * @brief Transfers SPI messages.
> + *
> + * The bus is obtained before the transfer and released afterwards.
> + *
> + * @param[in] bus The bus control.
> + * @param[in] msgs The messages to transfer.
> + * @param[in] msg_count The count of messages to transfer. It must be
> + * positive.
> + *
> + * @retval 0 Successful operation.
> + * @retval negative Negative error number in case of an error.
> + */
> +int spi_bus_transfer(spi_bus *bus, spi_ioc_transfer *msgs, uint32_t msg_count);
> +
> +/** @} */
> +
> +/**
> + * @defgroup SPIDevice SPI Device Driver
> + *
> + * @ingroup SPI
> + *
> + * @{
> + */
> +
> +/**
> + * @brief Base number for device IO control commands.
> + */
> +#define SPI_DEV_IO_CONTROL 0x900
> +
> +/**
> + * @brief SPI slave device control.
> + */
> +struct spi_dev {
> + /**
> + * @brief Reads from the device.
> + *
> + * @retval non-negative Bytes transferred from device.
> + * @retval negative Negative error number in case of an error.
> + */
> + ssize_t (*read)(spi_dev *dev, void *buf, size_t n, off_t offset);
> +
> + /**
> + * @brief Writes to the device.
> + *
> + * @retval non-negative Bytes transferred to device.
> + * @retval negative Negative error number in case of an error.
> + */
> + ssize_t (*write)(spi_dev *dev, const void *buf, size_t n, off_t offset);
> +
> + /**
> + * @brief Device IO control.
> + *
> + * @retval 0 Successful operation.
> + * @retval negative Negative error number in case of an error.
> + */
> + int (*ioctl)(spi_dev *dev, ioctl_command_t command, void *arg);
> +
> + /**
> + * @brief Gets the file size.
> + */
> + off_t (*get_size)(spi_dev *dev);
> +
> + /**
> + * @brief Gets the file block size.
> + */
> + blksize_t (*get_block_size)(spi_dev *dev);
> +
> + /**
> + * @brief Destroys the device.
> + */
> + void (*destroy)(spi_dev *dev);
> +
> + /**
> + * @brief The bus control.
> + */
> + spi_bus *bus;
> +
> + /**
> + * @brief The device address.
> + */
> + uint16_t address;
> +
> + /**
> + * @brief File descriptor of the bus.
> + *
> + * This prevents destruction of the bus since we hold a reference to it with
> + * this.
> + */
> + int bus_fd;
> +};
> +
> +
> +/**
> + * @brief Initializes a device control.
> + *
> + * After a sucessful initialization the device control must be destroyed via
> + * spi_dev_destroy(). A registered device control will be automatically
> + * destroyed in case the device file is unlinked. Make sure to call
> + * spi_dev_destroy_and_free() in a custom destruction handler.
> + *
> + * @param[in] device The device control.
> + * @param[in] bus_path The path to the bus device file.
> + * @param[in] address The address of the device.
> + *
> + * @retval 0 Successful operation.
> + * @retval -1 An error occurred. The errno is set to indicate the error.
> + *
> + * @see spi_dev_register()
> + */
> +int spi_dev_init(spi_dev *dev, const char *bus_path, uint16_t address);
> +
> +/**
> + * @brief Allocates a device control from the heap and initializes it.
> + *
> + * After a sucessful allocation and initialization the device control must be
> + * destroyed via spi_dev_destroy_and_free(). A registered device control will
> + * be automatically destroyed in case the device file is unlinked. Make sure
> + * to call spi_dev_destroy_and_free() in a custom destruction handler.
> + *
> + * @param[in] size The size of the device control. This enables the addition
> + * of device specific data to the base device control. The device control is
> + * zero initialized.
> + * @param[in] bus_path The path to the bus device file.
> + * @param[in] address The address of the device.
> + *
> + * @retval non-NULL The new device control.
> + * @retval NULL An error occurred. The errno is set to indicate the error.
> + *
> + * @see spi_dev_register()
> + */
> +spi_dev *spi_dev_alloc_and_init(
> + size_t size,
> + const char *bus_path,
> + uint16_t address
> +);
> +
> +/**
> + * @brief Destroys a device control.
> + *
> + * @param[in] dev The device control.
> + */
> +void spi_dev_destroy(spi_dev *dev);
> +
> +/**
> + * @brief Destroys a device control and frees its memory.
> + *
> + * @param[in] dev The device control.
> + */
> +void spi_dev_destroy_and_free(spi_dev *dev);
> +
> +/**
> + * @brief Registers a device control.
> + *
> + * This function claims ownership of the device control regardless if the
> + * registration is successful or not.
> + *
> + * @param[in] dev The dev control.
> + * @param[in] dev_path The path to the device file of the device.
> + *
> + * @retval 0 Successful operation.
> + * @retval -1 An error occurred. The errno is set to indicate the error.
> + */
> +int spi_dev_register(
> + spi_dev *dev,
> + const char *dev_path
> +);
> +
> +/** @} */ /* end of spi device driver */
> +
> +/** @} */
> +
> +#ifdef __cplusplus
> +}
> +#endif /* __cplusplus */
> +
> +#endif /* _DEV_SPI_SPI_H */
> diff --git a/cpukit/dev/include/linux/spi/spidev.h b/cpukit/dev/include/linux/spi/spidev.h
> new file mode 100644
> index 0000000..a5b7df3
> --- /dev/null
> +++ b/cpukit/dev/include/linux/spi/spidev.h
> @@ -0,0 +1,242 @@
> +/**
> + * @file
> + *
> + * @brief RTEMS Port of Linux SPI API
> + *
> + * @ingroup SPILinux
> + */
> +
> +/*
> + * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at embedded-brains.de>
> + *
> + * 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.
> + */
> +
> +#ifndef _UAPI_LINUX_SPI_H
> +#define _UAPI_LINUX_SPI_H
> +
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <sys/ioccom.h>
> +
> +/**
> + * @defgroup SPILinux Linux SPI User-Space API
> + *
> + * @ingroup SPI
> + *
> + * @brief RTEMS port of Linux SPI user-space API.
> + *
> + * Additional documentation is available through the Linux sources, see
> + *
> + * - /usr/src/linux/include/uapi/linux/spidev.h, and
> + * - /usr/src/linux/Documentation/spi.
> + *
> + * @{
> + */
> +
> +#define SPI_MESSAGE_SIZE_POS 16
> +#define SPI_MESSAGE_SIZE_BIT_LENGTH 14
> +
> +/**
> + * @name SPI Transfer Flags
> + *
> + * @{
> + */
> +
> +/**
> + * @brief SPI transfer flag which sets the clock phase.
> + */
> +#define SPI_CPHA 0x01
> +/**
> + * @brief SPI transfer flag which sets the clock polarity.
> + */
> +#define SPI_CPOL 0x02
> +
> +/**
> + * @brief SPI transfer flag which sets SPI Mode 0 (clock starts low, sample on
> + * leading edge).
> + */
> +#define SPI_MODE_0 (0|0)
> +/**
> + * @brief SPI transfer flag which sets SPI Mode 0 (clock starts low, sample on
> + * trailing edge).
> + */
> +#define SPI_MODE_1 (0|SPI_CPHA)
> +/**
> + * @brief SPI transfer flag which sets SPI Mode 0 (clock starts high, sample on
> + * leading edge).
> + */
> +#define SPI_MODE_2 (SPI_CPOL|0)
> +/**
> + * @brief SPI transfer flag which sets SPI Mode 0 (clock starts high, sample on
> + * trailing edge).
> + */
> +#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
> +
> +/**
> + * @brief SPI transfer flag which selects the device by setting the chip select
> + * line.
> + */
> +#define SPI_CS_HIGH 0x04
> +/**
> + * @brief SPI transfer flag which triggers data transmission with the LSB being
> + * sent first.
> + */
> +#define SPI_LSB_FIRST 0x08
> +/**
> + * @brief SPI transfer flag which uses a shared wire for master input/slave
> + * output as well as master output/slave input.
> + */
> +#define SPI_3WIRE 0x10
> +/**
> + * @brief SPI transfer flag which initiates the loopback mode.
> + */
> +#define SPI_LOOP 0x20
> +/**
> + * @brief SPI transfer flag which indicates that no chip select is needed due to
> + * only one device on the bus.
> + */
> +#define SPI_NO_CS 0x40
> +/**
> + * @brief SPI transfer flag which pulls the slave to low level during pause.
> + */
> +#define SPI_READY 0x80
> +/**
> + * @brief SPI transfer flag which sets up dual mode for transmission.
> + */
> +#define SPI_TX_DUAL 0x100
> +/**
> + * @brief SPI transfer flag which sets up quad mode for transmission.
> + */
> +#define SPI_TX_QUAD 0x200
> +/**
> + * @brief SPI transfer flag which sets up dual mode for reception.
> + */
> +#define SPI_RX_DUAL 0x400
> +/**
> + * @brief SPI transfer flag which sets up quad mode for reception.
> + */
> +#define SPI_RX_QUAD 0x800
> +
> +/** @} */
> +
> +#define SPI_IOC_MAGIC 's'
> +
> +#define SPI_IOC_TRANSFER_MAGIC 'p'
> +
> +/**
> + * @brief SPI Transfer Structure.
> + */
> +struct spi_ioc_transfer {
> + /**
> + * @brief Buffer for receive data.
> + */
> + void *rx_buf;
> +
> + /**
> + * @brief Buffer for transmit data.
> + */
> + const void *tx_buf;
> +
> + /**
> + * @brief Length of rx_buf and tx_buf in bytes.
> + */
> + size_t len;
> +
> + /**
> + * @brief Sets the bitrate of the device.
> + */
> + uint32_t speed_hz;
> +
> + /**
> + * @brief Sets the delay after a transfer before the chip select status is
> + * changed and the next transfer is triggered.
> + */
> + uint16_t delay_usecs;
> +
> + /**
> + * @brief Sets the device wordsize.
> + */
> + uint8_t bits_per_word;
> +
> + /**
> + * @brief If true, device is deselected after transfer ended and before a new
> + * transfer is started.
> + */
> + uint8_t cs_change;
> +
> + /**
> + * @brief Amount of bits that are used for reading.
> + */
> + uint8_t rx_nbits;
> +
> + /**
> + * @brief Amount of bits that are used for writing.
> + */
> + uint8_t tx_nbits;
> +
> + /**
> + * @brief Sets one of the possible modes that can be used for SPI transfers
> + * (dependent on clock phase and polarity).
> + */
> + uint32_t mode;
> +
> + /**
> + * @brief Indicates which device is currently used.
> + */
> + uint8_t cs;
> +};
> +
> +/**
> + * @brief Calculates the size of the SPI message.
> + */
> +#define SPI_MSGSIZE(N) \
> + ((((N)*(sizeof (struct spi_ioc_transfer))) \
> + < (1 << SPI_MESSAGE_SIZE_BIT_LENGTH)) \
> + ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
> +
> +/**
> + * @brief Transfers an array with SPI messages.
> + */
> +#define SPI_IOC_MESSAGE(n) \
> + _IOW(SPI_IOC_TRANSFER_MAGIC, n, struct spi_ioc_transfer)
> +
> +/**
> + * @brief Reads and writes the SPI mode field (restriction to 8 bits).
> + */
> +#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, uint8_t)
> +#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, uint8_t)
> +
> +/**
> + * @brief Reads and writes the SPI LSB field.
> + */
> +#define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, uint8_t)
> +#define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, uint8_t)
> +
> +/**
> + * @brief Reads and writes the SPI Bits per word field.
> + */
> +#define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC, 3, uint8_t)
> +#define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, uint8_t)
> +
> +/**
> + * @brief Reads and writes the SPI maximum rx/tx speed field.
> + */
> +#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, uint32_t)
> +#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, uint32_t)
> +
> +/**
> + * @brief Reads and writes the SPI mode field (extended to 32 bits).
> + */
> +#define SPI_IOC_RD_MODE32 _IOR(SPI_IOC_MAGIC, 5, uint32_t)
> +#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, uint32_t)
> +
> +#endif /* _UAPI_LINUX_SPI_H */
> diff --git a/cpukit/dev/spi/spi-bus.c b/cpukit/dev/spi/spi-bus.c
> new file mode 100644
> index 0000000..a64b93f
> --- /dev/null
> +++ b/cpukit/dev/spi/spi-bus.c
> @@ -0,0 +1,362 @@
> +/**
> + * @file
> + *
> + * @brief Inter-Integrated Circuit (SPI) Bus Implementation
> + *
> + * @ingroup SPIBus
> + */
> +
> +/*
> + * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at embedded-brains.de>
> + *
> + * 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.
> + */
> +
> +#if HAVE_CONFIG_H
> + #include "config.h"
> +#endif
> +
> +#include <dev/spi/spi.h>
> +
> +#include <rtems/imfs.h>
> +
> +#include <stdlib.h>
> +#include <string.h>
> +
> +void spi_bus_obtain(spi_bus *bus)
> +{
> + rtems_status_code sc;
> +
> + sc = rtems_semaphore_obtain(bus->mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
> + _Assert(sc == RTEMS_SUCCESSFUL);
> + (void) sc;
> +}
> +
> +void spi_bus_release(spi_bus *bus)
> +{
> + rtems_status_code sc;
> +
> + sc = rtems_semaphore_release(bus->mutex);
> + _Assert(sc == RTEMS_SUCCESSFUL);
> + (void) sc;
> +}
> +
> +int spi_bus_transfer(spi_bus *bus, spi_ioc_transfer *msgs, uint32_t msg_count)
> +{
> + int err;
> +
> + _Assert(msg_count > 0);
> +
> + spi_bus_obtain(bus);
> + err = (*bus->transfer)(bus, msgs, msg_count);
> + spi_bus_release(bus);
> +
> + return err;
> +}
> +
> +static ssize_t spi_bus_read(
> + rtems_libio_t *iop,
> + void *buffer,
> + size_t count
> +)
> +{
> + spi_bus *bus = IMFS_generic_get_context_by_iop(iop);
> + spi_ioc_transfer msg = {
> + .len = count,
> + .rx_buf = buffer,
> + .cs_change = bus->cs_change,
> + .cs = bus->data.cs,
> + .bits_per_word = bus->data.bits_per_word,
> + .mode = bus->data.mode,
> + .speed_hz = bus->data.speed_hz,
> + .delay_usecs = bus->data.delay_usecs
> + };
> + int err;
> +
> + err = spi_bus_transfer(bus, &msg, 1);
> + if (err == 0) {
> + return msg.len;
> + } else {
> + rtems_set_errno_and_return_minus_one(-err);
> + }
> +}
> +
> +static ssize_t spi_bus_write(
> + rtems_libio_t *iop,
> + const void *buffer,
> + size_t count
> +)
> +{
> + spi_bus *bus = IMFS_generic_get_context_by_iop(iop);
> + spi_ioc_transfer msg = {
> + .len = (uint16_t) count,
> + .tx_buf = RTEMS_DECONST(void *, buffer),
> + .cs_change = bus->cs_change,
> + .cs = bus->data.cs,
> + .bits_per_word = bus->data.bits_per_word,
> + .mode = bus->data.mode,
> + .speed_hz = bus->data.speed_hz,
> + .delay_usecs = bus->data.delay_usecs
> + };
> + int err;
> +
> + err = spi_bus_transfer(bus, &msg, 1);
> + if (err == 0) {
> + return msg.len;
> + } else {
> + rtems_set_errno_and_return_minus_one(-err);
> + }
> +}
> +
> +#if 1
> +static int spi_get_ioc_message(uint32_t cmd, size_t *n_ioc)
> +{
> + uint32_t tmp;
> +
> + tmp = (cmd >> SPI_MESSAGE_SIZE_POS) & ((1 << SPI_MESSAGE_SIZE_BIT_LENGTH)-1);
> + if ((tmp % sizeof(struct spi_ioc_transfer)) != 0){
> + return -EINVAL;
> + }
> + *n_ioc = tmp / sizeof(struct spi_ioc_transfer);
> +
> + return 0;
> +}
> +#endif
> +
> +static int spi_bus_ioctl(
> + rtems_libio_t *iop,
> + ioctl_command_t command,
> + void *arg
> +)
> +{
> + spi_bus *bus = IMFS_generic_get_context_by_iop(iop);
> + int err;
> + uint32_t msg_count;
> + struct spi_ioc_transfer *ioc;
> + int i;
> +
> + switch (command) {
> + case SPI_BUS_OBTAIN:
> + spi_bus_obtain(bus);
> + err = 0;
> + break;
> + case SPI_BUS_RELEASE:
> + spi_bus_release(bus);
> + err = 0;
> + break;
> + case SPI_BUS_GET_CONTROL:
> + *(spi_bus **) arg = bus;
> + err = 0;
> + break;
> + case SPI_BUS_SET_CLOCK:
> + spi_bus_obtain(bus);
> + err = (*bus->set_clock)(bus, (unsigned long) arg);
> + spi_bus_release(bus);
> + break;
> + case SPI_IOC_RD_MODE:
> + case SPI_IOC_RD_MODE32:
> + *(uint32_t *) arg = bus->data.mode;
> + err = 0;
> + break;
> + case SPI_IOC_RD_LSB_FIRST:
> + *(uint32_t *) arg = bus->lsb_first;
> + err = 0;
> + break;
> + case SPI_IOC_RD_BITS_PER_WORD:
> + *(uint32_t *) arg = bus->data.bits_per_word;
> + err = 0;
> + break;
> + case SPI_IOC_RD_MAX_SPEED_HZ:
> + *(uint32_t *) arg = bus->max_speed;
> + err = 0;
> + break;
> + case SPI_IOC_WR_MODE:
> + case SPI_IOC_WR_MODE32:
> + bus->data.mode = (uint32_t) arg;
> + err = 0;
> + break;
> + case SPI_IOC_WR_LSB_FIRST:
> + bus->lsb_first = (uint32_t) arg;
> + err = 0;
> + break;
> + case SPI_IOC_WR_BITS_PER_WORD:
> + bus->data.bits_per_word = (uint32_t) arg;
> + err = 0;
> + break;
> + case SPI_IOC_WR_MAX_SPEED_HZ:
> + bus->max_speed = (uint32_t) arg;
> + err = 0;
> + break;
> + default:
> + if (IOCGROUP(command) == SPI_IOC_TRANSFER_MAGIC) {
> + size_t n;
> +
> + err = spi_get_ioc_message(command, &n);
> + if (err == 0){
> + err = spi_bus_transfer(bus, arg, n);
> + }
> + } else {
> + err = -EINVAL;
> + }
> + break;
> + }
> +
> + if (err == 0) {
> + return 0;
> + } else {
> + rtems_set_errno_and_return_minus_one(-err);
> + }
> +}
> +
> +static const rtems_filesystem_file_handlers_r spi_bus_handler = {
> + .open_h = rtems_filesystem_default_open,
> + .close_h = rtems_filesystem_default_close,
> + .read_h = spi_bus_read,
> + .write_h = spi_bus_write,
> + .ioctl_h = spi_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 spi_bus_node_destroy(IMFS_jnode_t *node)
> +{
> + spi_bus *bus;
> +
> + bus = IMFS_generic_get_context_by_node(node);
> + (*bus->destroy)(bus);
> +
> + IMFS_node_destroy_default(node);
> +}
> +
> +static const IMFS_node_control spi_bus_node_control = IMFS_GENERIC_INITIALIZER(
> + &spi_bus_handler,
> + IMFS_node_initialize_generic,
> + spi_bus_node_destroy
> +);
> +
> +int spi_bus_register(
> + spi_bus *bus,
> + const char *bus_path
> +)
> +{
> + int rv;
> +
> + rv = IMFS_make_generic_node(
> + bus_path,
> + S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
> + &spi_bus_node_control,
> + bus
> + );
> + if (rv != 0) {
> + (*bus->destroy)(bus);
> + }
> +
> + return rv;
> +}
> +
> +static int spi_bus_transfer_default(
> + spi_bus *bus,
> + spi_ioc_transfer *msgs,
> + uint32_t msg_count
> +)
> +{
> + (void) bus;
> + (void) msgs;
> + (void) msg_count;
> +
> + return -EIO;
> +}
> +
> +static int spi_bus_set_clock_default(spi_bus *bus, unsigned long clock)
> +{
> + (void) bus;
> + (void) clock;
> +
> + return -EIO;
> +}
> +
> +static int spi_bus_do_init(
> + spi_bus *bus,
> + void (*destroy)(spi_bus *bus)
> +)
> +{
> + rtems_status_code sc;
> +
> + sc = rtems_semaphore_create(
> + rtems_build_name('S', 'P', 'I', ' '),
> + 1,
> + RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
> + 0,
> + &bus->mutex
> + );
> + if (sc != RTEMS_SUCCESSFUL) {
> + (*destroy)(bus);
> +
> + rtems_set_errno_and_return_minus_one(ENOMEM);
> + }
> +
> + bus->transfer = spi_bus_transfer_default;
> + bus->set_clock = spi_bus_set_clock_default;
> + bus->destroy = destroy;
> + /* Default max speed */
> + bus->max_speed = 50000000;
> +
> + return 0;
> +}
> +
> +void spi_bus_destroy(spi_bus *bus)
> +{
> + rtems_status_code sc;
> +
> + sc = rtems_semaphore_delete(bus->mutex);
> + _Assert(sc == RTEMS_SUCCESSFUL);
> + (void) sc;
> +}
> +
> +void spi_bus_destroy_and_free(spi_bus *bus)
> +{
> + spi_bus_destroy(bus);
> + free(bus);
> +}
> +
> +int spi_bus_init(spi_bus *bus)
> +{
> + memset(bus, 0, sizeof(*bus));
> +
> + return spi_bus_do_init(bus, spi_bus_destroy);
> +}
> +
> +spi_bus *spi_bus_alloc_and_init(size_t size)
> +{
> + spi_bus *bus = NULL;
> +
> + if (size >= sizeof(*bus)) {
> + bus = calloc(1, size);
> + if (bus != NULL) {
> + int rv;
> +
> + rv = spi_bus_do_init(bus, spi_bus_destroy_and_free);
> + if (rv != 0) {
> + return NULL;
> + }
> + }
> + }
> +
> + return bus;
> +}
> diff --git a/cpukit/dev/spi/spi-dev.c b/cpukit/dev/spi/spi-dev.c
> new file mode 100644
> index 0000000..72309ef
> --- /dev/null
> +++ b/cpukit/dev/spi/spi-dev.c
> @@ -0,0 +1,291 @@
> +/**
> + * @file
> + *
> + * @brief Inter-Integrated Circuit (SPI) Bus Implementation
> + *
> + * @ingroup SPIDevice
> + */
> +
> +/*
> + * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at embedded-brains.de>
> + *
> + * 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.
> + */
> +
> +#if HAVE_CONFIG_H
> + #include "config.h"
> +#endif
> +
> +#include <dev/spi/spi.h>
> +
> +#include <rtems/imfs.h>
> +#include <rtems/score/assert.h>
> +
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +
> +static ssize_t spi_dev_read(
> + rtems_libio_t *iop,
> + void *buffer,
> + size_t count
> +)
> +{
> + spi_dev *dev = IMFS_generic_get_context_by_iop(iop);
> + ssize_t n;
> +
> + n = (*dev->read)(dev, buffer, count, iop->offset);
> + if (n >= 0) {
> + iop->offset += n;
> +
> + return n;
> + } else {
> + rtems_set_errno_and_return_minus_one(-n);
> + }
> +}
> +
> +static ssize_t spi_dev_write(
> + rtems_libio_t *iop,
> + const void *buffer,
> + size_t count
> +)
> +{
> + spi_dev *dev = IMFS_generic_get_context_by_iop(iop);
> + ssize_t n;
> +
> + n = (*dev->write)(dev, buffer, count, iop->offset);
> + if (n >= 0) {
> + iop->offset += n;
> +
> + return n;
> + } else {
> + rtems_set_errno_and_return_minus_one(-n);
> + }
> +}
> +
> +static int spi_dev_ioctl(
> + rtems_libio_t *iop,
> + ioctl_command_t command,
> + void *arg
> +)
> +{
> + spi_dev *dev = IMFS_generic_get_context_by_iop(iop);
> + int err;
> +
> + err = (*dev->ioctl)(dev, command, arg);
> +
> + if (err == 0) {
> + return 0;
> + } else {
> + rtems_set_errno_and_return_minus_one(-err);
> + }
> +}
> +
> +static int spi_dev_fstat(
> + const rtems_filesystem_location_info_t *loc,
> + struct stat *buf
> +)
> +{
> + spi_dev *dev = IMFS_generic_get_context_by_location(loc);
> +
> + buf->st_size = (*dev->get_size)(dev);
> + buf->st_blksize = (*dev->get_block_size)(dev);
> +
> + return IMFS_stat(loc, buf);
> +}
> +
> +static const rtems_filesystem_file_handlers_r spi_dev_handler = {
> + .open_h = rtems_filesystem_default_open,
> + .close_h = rtems_filesystem_default_close,
> + .read_h = spi_dev_read,
> + .write_h = spi_dev_write,
> + .ioctl_h = spi_dev_ioctl,
> + .lseek_h = rtems_filesystem_default_lseek_file,
> + .fstat_h = spi_dev_fstat,
> + .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 spi_dev_node_destroy(IMFS_jnode_t *node)
> +{
> + spi_dev *dev;
> +
> + dev = IMFS_generic_get_context_by_node(node);
> + (*dev->destroy)(dev);
> +
> + IMFS_node_destroy_default(node);
> +}
> +
> +static const IMFS_node_control spi_dev_node_control = IMFS_GENERIC_INITIALIZER(
> + &spi_dev_handler,
> + IMFS_node_initialize_generic,
> + spi_dev_node_destroy
> +);
> +
> +int spi_dev_register(
> + spi_dev *dev,
> + const char *dev_path
> +)
> +{
> + int rv;
> +
> + rv = IMFS_make_generic_node(
> + dev_path,
> + S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
> + &spi_dev_node_control,
> + dev
> + );
> + if (rv != 0) {
> + (*dev->destroy)(dev);
> + }
> +
> + return rv;
> +}
> +
> +static ssize_t spi_dev_read_default(
> + spi_dev *dev,
> + void *buf,
> + size_t n,
> + off_t offset
> +)
> +{
> + (void) dev;
> + (void) buf;
> + (void) n;
> + (void) offset;
> +
> + return -EIO;
> +}
> +
> +static ssize_t spi_dev_write_default(
> + spi_dev *dev,
> + const void *buf,
> + size_t n,
> + off_t offset
> +)
> +{
> + (void) dev;
> + (void) buf;
> + (void) n;
> + (void) offset;
> +
> + return -EIO;
> +}
> +
> +static int spi_dev_ioctl_default(
> + spi_dev *dev,
> + ioctl_command_t command,
> + void *arg
> +)
> +{
> + (void) dev;
> + (void) command;
> + (void) arg;
> +
> + return -ENOTTY;
> +}
> +
> +static off_t spi_dev_get_size_default(spi_dev *dev)
> +{
> + (void) dev;
> +
> + return 0;
> +}
> +
> +static blksize_t spi_dev_get_block_size_default(spi_dev *dev)
> +{
> + (void) dev;
> +
> + return 1;
> +}
> +
> +static int spi_dev_do_init(
> + spi_dev *dev,
> + const char *bus_path,
> + uint16_t address,
> + void (*destroy)(spi_dev *dev)
> +)
> +{
> + int rv;
> +
> + dev->bus_fd = open(bus_path, O_RDWR);
> + if (dev->bus_fd < 0) {
> + (*destroy)(dev);
> +
> + return -1;
> + }
> +
> + rv = ioctl(dev->bus_fd, SPI_BUS_GET_CONTROL, &dev->bus);
> + if (rv != 0) {
> + (*destroy)(dev);
> +
> + return -1;
> + }
> +
> + dev->read = spi_dev_read_default;
> + dev->write = spi_dev_write_default;
> + dev->ioctl = spi_dev_ioctl_default;
> + dev->get_size = spi_dev_get_size_default;
> + dev->get_block_size = spi_dev_get_block_size_default;
> + dev->destroy = destroy;
> + dev->address = address;
> +
> + return 0;
> +}
> +
> +void spi_dev_destroy(spi_dev *dev)
> +{
> + int rv;
> +
> + rv = close(dev->bus_fd);
> + _Assert(dev->bus_fd < 0 || rv == 0);
> + (void) rv;
> +}
> +
> +void spi_dev_destroy_and_free(spi_dev *dev)
> +{
> + spi_dev_destroy(dev);
> + free(dev);
> +}
> +
> +int spi_dev_init(spi_dev *dev, const char *bus_path, uint16_t address)
> +{
> + return spi_dev_do_init(dev, bus_path, address, spi_dev_destroy);
> +}
> +
> +spi_dev *spi_dev_alloc_and_init(
> + size_t size,
> + const char *bus_path,
> + uint16_t address
> +)
> +{
> + spi_dev *dev = NULL;
> +
> + if (size >= sizeof(*dev)) {
> + dev = calloc(1, size);
> + if (dev != NULL) {
> + int rv;
> +
> + rv = spi_dev_do_init(dev, bus_path, address, spi_dev_destroy_and_free);
> + if (rv != 0) {
> + return NULL;
> + }
> + }
> + }
> +
> + return dev;
> +}
> diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am
> index dbd96cb..c00916a 100644
> --- a/testsuites/libtests/Makefile.am
> +++ b/testsuites/libtests/Makefile.am
> @@ -9,6 +9,7 @@ _SUBDIRS += pwdgrp01
> _SUBDIRS += crypt01
> _SUBDIRS += sha
> _SUBDIRS += i2c01
> +_SUBDIRS += spi01
> _SUBDIRS += newlib01
> _SUBDIRS += block17
> _SUBDIRS += exit02
> diff --git a/testsuites/libtests/spi01/buffer_test_io.h b/testsuites/libtests/spi01/buffer_test_io.h
> new file mode 100644
> index 0000000..ac73352
> --- /dev/null
> +++ b/testsuites/libtests/spi01/buffer_test_io.h
> @@ -0,0 +1,219 @@
> +/*
> + * Support for running the test output through a buffer
> + */
> +
> +#ifndef __BUFFER_TEST_IO_h
> +#define __BUFFER_TEST_IO_h
> +
> +#include <rtems/bspIo.h>
> +#include <rtems/test.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +/*
> + * Uncomment this to get buffered test output. When commented out,
> + * test output behaves as it always has and is printed using stdio.
> + */
> +
> +/* #define TESTS_BUFFER_OUTPUT */
> +/* #define TESTS_USE_PRINTK */
> +
> +/*
> + * USE PRINTK TO MINIMIZE SIZE
> + */
> +#if defined(TESTS_USE_PRINTK)
> +
> +#include <rtems/print.h>
> +
> + #undef printf
> + #define printf(...) \
> + do { \
> + printk( __VA_ARGS__); \
> + } while (0)
> +
> + #undef puts
> + #define puts(_s) \
> + do { \
> + printk( "%s\n", _s); \
> + } while (0)
> +
> + #undef putchar
> + #define putchar(_c) \
> + do { \
> + printk( "%c", _c ); \
> + } while (0)
> +
> + /* Do not call exit() since it closes stdin, etc and pulls in stdio code */
> + #define rtems_test_exit(_s) \
> + do { \
> + rtems_shutdown_executive(0); \
> + } while (0)
> +
> + #define FLUSH_OUTPUT() \
> + do { \
> + } while (0)
> +
> + #define TEST_BEGIN() printk(TEST_BEGIN_STRING)
> +
> + #define TEST_END() printk(TEST_END_STRING)
> +
> +/*
> + * BUFFER TEST OUTPUT
> + */
> +#elif defined(TESTS_BUFFER_OUTPUT)
> +
> + #include <stdio.h>
> + #include <stdlib.h>
> +
> + #define _TEST_OUTPUT_BUFFER_SIZE 2048
> + extern char _test_output_buffer[_TEST_OUTPUT_BUFFER_SIZE];
> + void _test_output_append(char *);
> + void _test_output_flush(void);
> +
> + #define rtems_test_exit(_s) \
> + do { \
> + _test_output_flush(); \
> + exit(_s); \
> + } while (0)
> +
> + #undef printf
> + #define printf(...) \
> + do { \
> + char _buffer[128]; \
> + sprintf( _buffer, __VA_ARGS__); \
> + _test_output_append( _buffer ); \
> + } while (0)
> +
> + #undef puts
> + #define puts(_string) \
> + do { \
> + char _buffer[128]; \
> + sprintf( _buffer, "%s\n", _string ); \
> + _test_output_append( _buffer ); \
> + } while (0)
> +
> + #undef putchar
> + #define putchar(_c) \
> + do { \
> + char _buffer[2]; \
> + _buffer[0] = _c; \
> + _buffer[1] = '\0'; \
> + _test_output_append( _buffer ); \
> + } while (0)
> +
> + /* we write to stderr when there is a pause() */
> + #define FLUSH_OUTPUT() _test_output_flush()
> +
> + #if defined(TEST_INIT) || defined(CONFIGURE_INIT)
> +
> + char _test_output_buffer[_TEST_OUTPUT_BUFFER_SIZE];
> + int _test_output_buffer_index = 0;
> +
> + void _test_output_append(char *_buffer)
> + {
> + char *p;
> +
> + for ( p=_buffer ; *p ; p++ ) {
> + _test_output_buffer[_test_output_buffer_index++] = *p;
> + _test_output_buffer[_test_output_buffer_index] = '\0';
> + #if 0
> + if ( *p == '\n' ) {
> + fprintf( stderr, "BUFFER -- %s", _test_output_buffer );
> + _test_output_buffer_index = 0;
> + _test_output_buffer[0] = '\0';
> + }
> + #endif
> + if ( _test_output_buffer_index >= (_TEST_OUTPUT_BUFFER_SIZE - 80) )
> + _test_output_flush();
> + }
> + }
> +
> + #include <termios.h>
> + #include <unistd.h>
> +
> + void _test_output_flush(void)
> + {
> + fprintf( stderr, "%s", _test_output_buffer );
> + _test_output_buffer_index = 0;
> + tcdrain( 2 );
> + }
> +
> + #endif
> +
> +#elif defined(TESTS_USE_PRINTF)
> +
> + #include <stdio.h>
> + #include <stdlib.h>
> +
> + #define rtems_test_exit(_s) \
> + do { \
> + exit(_s); \
> + } while (0)
> +
> + #define FLUSH_OUTPUT() \
> + do { \
> + fflush(stdout); \
> + } while (0)
> +
> + #define TEST_BEGIN() printf(TEST_BEGIN_STRING)
> +
> + #define TEST_END() printf(TEST_END_STRING)
> +
> +/*
> + * USE IPRINT
> + */
> +#else
> +
> + #include <stdio.h>
> + #include <stdlib.h>
> +
> + /* do not use iprintf if strict ansi mode */
> + #if defined(_NEWLIB_VERSION) && !defined(__STRICT_ANSI__)
> + #undef printf
> + #define printf(...) \
> + do { \
> + fiprintf( stderr, __VA_ARGS__ ); \
> + } while (0)
> + #else
> + #undef printf
> + #define printf(...) \
> + do { \
> + fprintf( stderr, __VA_ARGS__ ); \
> + } while (0)
> + #endif
> +
> + #undef puts
> + #define puts(_s) \
> + do { \
> + printf( "%s\n", _s ); \
> + } while (0)
> +
> + #undef putchar
> + #define putchar(_c) \
> + do { \
> + printf( "%c", _c ); \
> + } while (0)
> +
> + #define rtems_test_exit(_s) \
> + do { \
> + exit(_s); \
> + } while (0)
> +
> + #define FLUSH_OUTPUT() \
> + do { \
> + fflush(stdout); \
> + } while (0)
> +
> + #define TEST_BEGIN() fiprintf( stderr, TEST_BEGIN_STRING)
> +
> + #define TEST_END() fiprintf( stderr, TEST_END_STRING)
> +
> +#endif
> +
> +#ifdef __cplusplus
> +};
> +#endif
> +
> +#endif
> diff --git a/testsuites/libtests/spi01/init.c b/testsuites/libtests/spi01/init.c
> new file mode 100644
> index 0000000..e80ad18
> --- /dev/null
> +++ b/testsuites/libtests/spi01/init.c
> @@ -0,0 +1,256 @@
> +/*
> + * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at embedded-brains.de>
> + *
> + * 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.
> + */
> +
> +#ifdef HAVE_CONFIG_H
> + #include "config.h"
> +#endif
> +
> +#include <dev/spi/spi.h>
> +
> +#include <sys/ioctl.h>
> +#include <sys/stat.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include <rtems/libcsupport.h>
> +
> +#include "tmacros.h"
> +
> +const char rtems_test_name[] = "SPI 1";
> +
> +typedef struct test_device test_device;
> +
> +struct test_device {
> + int (*transfer)(
> + spi_bus *bus,
> + spi_ioc_transfer *msgs,
> + uint32_t msg_count,
> + test_device *dev
> + );
> +};
> +
> +typedef struct {
> + test_device base;
> + char buf[3];
> +} test_device_simple_read_write;
> +
> +typedef struct {
> + spi_bus base;
> + unsigned long clock;
> + test_device *device;
> + test_device_simple_read_write simple_read_write;
> +} test_bus;
> +
> +static const char bus_path[] = "/dev/spi-0";
> +
> +static int test_simple_read_write_transfer(
> + spi_bus *bus,
> + spi_ioc_transfer *msgs,
> + uint32_t msg_count,
> + test_device *base
> +)
> +{
> + (void)bus;
> +
> + test_device_simple_read_write *dev = (test_device_simple_read_write *) base;
> +
> + if (msg_count == 1 && msgs[0].len == sizeof(dev->buf)) {
> + if (msgs[0].rx_buf == 0){
> + memcpy(&dev->buf[0], msgs[0].tx_buf, sizeof(dev->buf));
> + } else if (msgs[0].tx_buf == 0){
> + memcpy(msgs[0].rx_buf, &dev->buf[0], sizeof(dev->buf));
> + } else {
> + return -EIO;
> + }
> + } else {
> + return -EIO;
> + }
> + return 0;
> +}
> +
> +static int test_transfer(spi_bus *base, spi_ioc_transfer *msgs, uint32_t msg_count)
> +{
> + test_bus *bus = (test_bus *) base;
> + test_device *dev;
> +
> + dev = bus->device;
> +
> + return (*dev->transfer)(&bus->base, msgs, msg_count, dev);
> +}
> +
> +static int test_set_clock(spi_bus *base, unsigned long clock)
> +{
> + test_bus *bus = (test_bus *) base;
> +
> + bus->clock = clock;
> +
> + return 0;
> +}
> +
> +static void test_destroy(spi_bus *base)
> +{
> + spi_bus_destroy_and_free(base);
> +}
> +
> +static void test_simple_read_write(test_bus *bus, int fd)
> +{
> + static const char zero[] = { 0, 0, 0 };
> + static const char abc[] = { 'a', 'b', 'c' };
> +
> + int rv;
> + char buf[3];
> + ssize_t n;
> +
> + errno = 0;
> + rv = ioctl(fd, 0xb00b);
> + rtems_test_assert(rv == -1);
> + rtems_test_assert(errno == ENOTTY);
> +
> + errno = 0;
> + n = write(fd, &buf[0], 1000);
> + rtems_test_assert(n == -1);
> + rtems_test_assert(errno == EIO);
> +
> + errno = 0;
> + n = read(fd, &buf[0], 1000);
> + rtems_test_assert(n == -1);
> + rtems_test_assert(errno == EIO);
> +
> + rtems_test_assert(
> + memcmp(&bus->simple_read_write.buf[0], &zero[0], sizeof(buf)) == 0
> + );
> +
> + n = write(fd, &abc[0], sizeof(buf));
> + rtems_test_assert(n == (ssize_t) sizeof(buf));
> +
> + rtems_test_assert(
> + memcmp(&bus->simple_read_write.buf[0], &abc[0], sizeof(buf)) == 0
> + );
> +
> + n = read(fd, &buf[0], sizeof(buf));
> + rtems_test_assert(n == (ssize_t) sizeof(buf));
> +
> + rtems_test_assert(memcmp(&buf[0], &abc[0], sizeof(buf)) == 0);
> +}
> +
> +static void test(void)
> +{
> + rtems_resource_snapshot snapshot;
> + test_bus *bus;
> + int rv;
> + int fd;
> +
> + rtems_resource_snapshot_take(&snapshot);
> +
> + bus = (test_bus *) spi_bus_alloc_and_init(sizeof(*bus));
> + rtems_test_assert(bus != NULL);
> +
> + bus->base.transfer = test_transfer;
> + bus->base.set_clock = test_set_clock;
> + bus->base.destroy = test_destroy;
> +
> + bus->simple_read_write.base.transfer = test_simple_read_write_transfer;
> + bus->device = &bus->simple_read_write.base;
> +
> + rv = spi_bus_register(&bus->base, &bus_path[0]);
> + rtems_test_assert(rv == 0);
> +
> + fd = open(&bus_path[0], O_RDWR);
> + rtems_test_assert(fd >= 0);
> +
> + rtems_test_assert(bus->clock == 0);
> + rv = ioctl(fd, SPI_BUS_SET_CLOCK, 0xdeadbeefUL);
> + rtems_test_assert(rv == 0);
> + rtems_test_assert(bus->clock == 0xdeadbeef);
> +
> + rv = ioctl(fd, SPI_BUS_OBTAIN);
> + rtems_test_assert(rv == 0);
> +
> + rv = ioctl(fd, SPI_BUS_RELEASE);
> + rtems_test_assert(rv == 0);
> +
> + rv = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, 0x12345678);
> + rtems_test_assert(rv == 0);
> + rv = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &bus->base.max_speed);
> + rtems_test_assert(rv == 0);
> + rtems_test_assert(bus->base.max_speed == 0x12345678);
> +
> + rv = ioctl(fd, SPI_IOC_WR_LSB_FIRST, 1);
> + rtems_test_assert(rv == 0);
> + rv = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bus->base.lsb_first);
> + rtems_test_assert(rv == 0);
> + rtems_test_assert(bus->base.lsb_first == 1);
> +
> + rv = ioctl(fd, SPI_IOC_WR_MODE, 0xA5);
> + rtems_test_assert(rv == 0);
> + rv = ioctl(fd, SPI_IOC_RD_MODE, &bus->base.data.mode);
> + rtems_test_assert(rv == 0);
> + rtems_test_assert(bus->base.data.mode == 0xA5);
> +
> + rv = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, 8);
> + rtems_test_assert(rv == 0);
> + rv = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bus->base.data.bits_per_word);
> + rtems_test_assert(rv == 0);
> + rtems_test_assert(bus->base.data.bits_per_word == 8);
> +
> + rv = ioctl(fd, SPI_IOC_WR_MODE32, 0x5A5A5A5A);
> + rtems_test_assert(rv == 0);
> + rv = ioctl(fd, SPI_IOC_RD_MODE32, &bus->base.data.mode);
> + rtems_test_assert(rv == 0);
> + rtems_test_assert(bus->base.data.mode == 0x5A5A5A5A);
> +
> + test_simple_read_write(bus, fd);
> +
> + rv = close(fd);
> + rtems_test_assert(rv == 0);
> +
> + rv = unlink(&bus_path[0]);
> + rtems_test_assert(rv == 0);
> +
> + rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
> +}
> +
> +static void Init(rtems_task_argument arg)
> +{
> + (void)arg;
> +
> + TEST_BEGIN();
> +
> + test();
> +
> + TEST_END();
> + rtems_test_exit(0);
> +}
> +
> +#define CONFIGURE_MICROSECONDS_PER_TICK 2000
> +
> +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
> +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
> +
> +#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 7
> +
> +#define CONFIGURE_MAXIMUM_TASKS 1
> +
> +#define CONFIGURE_MAXIMUM_SEMAPHORES 1
> +
> +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
> +
> +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
> +
> +#define CONFIGURE_INIT
> +
> +#include <rtems/confdefs.h>
> diff --git a/testsuites/libtests/spi01/spi01.doc b/testsuites/libtests/spi01/spi01.doc
> new file mode 100644
> index 0000000..754aa8a
> --- /dev/null
> +++ b/testsuites/libtests/spi01/spi01.doc
> @@ -0,0 +1,11 @@
> +This file describes the directives and concepts tested by this test set.
> +
> +test set name: spi01
> +
> +directives:
> +
> + TBD
> +
> +concepts:
> +
> + - Ensure that the SPI driver framework works.
> diff --git a/testsuites/libtests/spi01/spi01.scn b/testsuites/libtests/spi01/spi01.scn
> new file mode 100644
> index 0000000..6d8f6cc
> --- /dev/null
> +++ b/testsuites/libtests/spi01/spi01.scn
> @@ -0,0 +1,2 @@
> +*** BEGIN OF TEST SPI 1 ***
> +*** END OF TEST SPI 1 ***
> diff --git a/testsuites/libtests/spi01/tmacros.h b/testsuites/libtests/spi01/tmacros.h
> new file mode 100644
> index 0000000..d8aec2a
> --- /dev/null
> +++ b/testsuites/libtests/spi01/tmacros.h
> @@ -0,0 +1,372 @@
> +/**
> + * @file
> + *
> + * This include file contains macros which are useful in the RTEMS
> + * test suites.
> + */
> +
> +/*
> + * COPYRIGHT (c) 1989-2014.
> + * On-Line Applications Research Corporation (OAR).
> + *
> + * 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.
> + */
> +
> +#ifndef __TMACROS_h
> +#define __TMACROS_h
> +
> +#include <inttypes.h>
> +#include <bsp.h> /* includes <rtems.h> */
> +
> +#include <ctype.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <rtems/error.h>
> +#include <rtems/test.h>
> +#include <rtems/score/threaddispatch.h>
> +
> +#include <buffer_test_io.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#define FOREVER 1 /* infinite loop */
> +
> +#ifdef CONFIGURE_INIT
> +#define TEST_EXTERN
> +#else
> +#define TEST_EXTERN extern
> +#endif
> +
> +/*
> + * Check that that the dispatch disable level is proper for the
> + * mode/state of the test. Normally it should be 0 when in task space.
> + *
> + * This test is only valid when in a non-SMP system. In an smp system
> + * another cpu may be accessing the core at any point when this core
> + * does not have it locked.
> + */
> +#if defined SMPTEST
> + #define check_dispatch_disable_level( _expect )
> +#else
> + #define check_dispatch_disable_level( _expect ) \
> + do { \
> + if ( (_expect) != -1 \
> + && (((!_Thread_Dispatch_is_enabled()) == false && (_expect) != 0) \
> + || ((!_Thread_Dispatch_is_enabled()) && (_expect) == 0)) \
> + ) { \
> + printk( \
> + "\n_Thread_Dispatch_disable_level is (%i)" \
> + " not %d detected at %s:%d\n", \
> + !_Thread_Dispatch_is_enabled(), (_expect), __FILE__, __LINE__ ); \
> + FLUSH_OUTPUT(); \
> + rtems_test_exit( 1 ); \
> + } \
> + } while ( 0 )
> +#endif
> +
> +/*
> + * Check that that the allocator mutex is not owned by the executing thread.
> + */
> +#include <rtems/score/apimutex.h>
> +#define check_if_allocator_mutex_is_not_owned() \
> + do { \
> + if ( _RTEMS_Allocator_is_owner() ) { \
> + printk( \
> + "\nRTEMS Allocator Mutex is owned by executing thread " \
> + "and should not be.\n" \
> + "Detected at %s:%d\n", \
> + __FILE__, \
> + __LINE__ \
> + ); \
> + FLUSH_OUTPUT(); \
> + rtems_test_exit( 1 ); \
> + } \
> + } while ( 0 )
> +
> +/*
> + * These macros properly report errors within the Classic API
> + */
> +#define directive_failed( _dirstat, _failmsg ) \
> + fatal_directive_status( _dirstat, RTEMS_SUCCESSFUL, _failmsg )
> +
> +#define directive_failed_with_level( _dirstat, _failmsg, _level ) \
> + fatal_directive_status_with_level( \
> + _dirstat, RTEMS_SUCCESSFUL, _failmsg, _level )
> +
> +#define fatal_directive_status( _stat, _desired, _msg ) \
> + fatal_directive_status_with_level( _stat, _desired, _msg, 0 )
> +
> +#define fatal_directive_check_status_only( _stat, _desired, _msg ) \
> + do { \
> + if ( (_stat) != (_desired) ) { \
> + printf( "\n%s FAILED -- expected (%s) got (%s)\n", \
> + (_msg), rtems_status_text(_desired), rtems_status_text(_stat) ); \
> + FLUSH_OUTPUT(); \
> + rtems_test_exit( _stat ); \
> + } \
> + } while ( 0 )
> +
> +#define fatal_directive_status_with_level( _stat, _desired, _msg, _level ) \
> + do { \
> + check_dispatch_disable_level( _level ); \
> + check_if_allocator_mutex_is_not_owned(); \
> + fatal_directive_check_status_only( _stat, _desired, _msg ); \
> + } while ( 0 )
> +
> +/*
> + * These macros properly report errors from the POSIX API
> + */
> +
> +#define posix_service_failed( _dirstat, _failmsg ) \
> + fatal_posix_service_status( _dirstat, 0, _failmsg )
> +
> +#define posix_service_failed_with_level( _dirstat, _failmsg, _level ) \
> + fatal_posix_service_status_with_level( _dirstat, 0, _failmsg, _level )
> +
> +#define fatal_posix_service_status_errno( _stat, _desired, _msg ) \
> + if ( (_stat != -1) && (errno) != (_desired) ) { \
> + long statx = _stat; \
> + check_dispatch_disable_level( 0 ); \
> + check_if_allocator_mutex_is_not_owned(); \
> + printf( "\n%s FAILED -- expected (%d - %s) got (%ld %d - %s)\n", \
> + (_msg), _desired, strerror(_desired), \
> + statx, errno, strerror(errno) ); \
> + FLUSH_OUTPUT(); \
> + rtems_test_exit( _stat ); \
> + }
> +
> +#define fatal_posix_service_status( _stat, _desired, _msg ) \
> + fatal_posix_service_status_with_level( _stat, _desired, _msg, 0 )
> +
> +#define fatal_posix_service_status_with_level( _stat, _desired, _msg, _level ) \
> + do { \
> + check_dispatch_disable_level( _level ); \
> + check_if_allocator_mutex_is_not_owned(); \
> + if ( (_stat) != (_desired) ) { \
> + printf( "\n%s FAILED -- expected (%d - %s) got (%d - %s)\n", \
> + (_msg), _desired, strerror(_desired), _stat, strerror(_stat) ); \
> + printf( "\n FAILED -- errno (%d - %s)\n", \
> + errno, strerror(errno) ); \
> + FLUSH_OUTPUT(); \
> + rtems_test_exit( _stat ); \
> + } \
> + } while ( 0 )
> +
> +/*
> + * This macro evaluates the semaphore id returned.
> + */
> +#define fatal_posix_sem( _ptr, _msg ) \
> + if ( (_ptr != SEM_FAILED) ) { \
> + check_dispatch_disable_level( 0 ); \
> + printf( "\n%s FAILED -- expected (-1) got (%p - %d/%s)\n", \
> + (_msg), _ptr, errno, strerror(errno) ); \
> + FLUSH_OUTPUT(); \
> + rtems_test_exit( -1 ); \
> + }
> +
> +/*
> + * This macro evaluates the message queue id returned.
> + */
> +#define fatal_posix_mqd( _ptr, _msg ) \
> + if ( (_ptr != (mqd_t) -1) ) { \
> + check_dispatch_disable_level( 0 ); \
> + printf( "\n%s FAILED -- expected (-1) got (%" PRId32 " - %d/%s)\n", \
> + (_msg), _ptr, errno, strerror(errno) ); \
> + FLUSH_OUTPUT(); \
> + rtems_test_exit( -1 ); \
> + }
> +
> +/*
> + * Generic integer version of the error reporting
> + */
> +
> +#define int_service_failed( _dirstat, _failmsg ) \
> + fatal_int_service_status( _dirstat, RTEMS_SUCCESSFUL, _failmsg )
> +
> +#define int_service_failed_with_level( _dirstat, _failmsg, _level ) \
> + fatal_int_service_status_with_level( \
> + _dirstat, RTEMS_SUCCESSFUL, _failmsg, _level )
> +
> +#define fatal_int_service_status( _stat, _desired, _msg ) \
> + fatal_int_service_status_with_level( _stat, _desired, _msg, 0 )
> +
> +#define fatal_int_service_status_with_level( _stat, _desired, _msg, _level ) \
> + do { \
> + check_dispatch_disable_level( _level ); \
> + if ( (_stat) != (_desired) ) { \
> + printf( "\n%s FAILED -- expected (%d) got (%d)\n", \
> + (_msg), (_desired), (_stat) ); \
> + FLUSH_OUTPUT(); \
> + rtems_test_exit( _stat ); \
> + } \
> + } while ( 0 )
> +
> +
> +/*
> + * Print the time
> + */
> +
> +#define sprint_time(_str, _s1, _tb, _s2) \
> + do { \
> + sprintf( (_str), "%s%02d:%02d:%02d %02d/%02d/%04d%s", \
> + _s1, (_tb)->hour, (_tb)->minute, (_tb)->second, \
> + (_tb)->month, (_tb)->day, (_tb)->year, _s2 ); \
> + } while ( 0 )
> +
> +#define print_time(_s1, _tb, _s2) \
> + do { \
> + printf( "%s%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 " %02" PRIu32 "/%02" PRIu32 "/%04" PRIu32 "%s", \
> + _s1, (_tb)->hour, (_tb)->minute, (_tb)->second, \
> + (_tb)->month, (_tb)->day, (_tb)->year, _s2 ); \
> + } while ( 0 )
> +
> +#define put_dot( _c ) \
> + do { \
> + putchar( _c ); \
> + FLUSH_OUTPUT(); \
> + } while ( 0 )
> +
> +#define new_line puts( "" )
> +
> +#define puts_nocr printf
> +
> +#ifdef RTEMS_TEST_NO_PAUSE
> +#define rtems_test_pause() \
> + do { \
> + printf( "<pause>\n" ); \
> + FLUSH_OUTPUT(); \
> + } while ( 0 )
> +
> +#define rtems_test_pause_and_screen_number( _screen ) \
> + do { \
> + printf( "<pause - screen %d>\n", (_screen) ); \
> + FLUSH_OUTPUT(); \
> + } while ( 0 )
> +#else
> +#define rtems_test_pause() \
> + do { \
> + char buffer[ 80 ]; \
> + printf( "<pause>" ); \
> + FLUSH_OUTPUT(); \
> + gets( buffer ); \
> + puts( "" ); \
> + } while ( 0 )
> +
> +#define rtems_test_pause_and_screen_number( _screen ) \
> + do { \
> + char buffer[ 80 ]; \
> + printf( "<pause - screen %d>", (_screen) ); \
> + FLUSH_OUTPUT(); \
> + gets( buffer ); \
> + puts( "" ); \
> + } while ( 0 )
> +#endif
> +
> +#define put_name( name, crlf ) \
> +{ int c0, c1, c2, c3; \
> + c0 = (name >> 24) & 0xff; \
> + c1 = (name >> 16) & 0xff; \
> + c2 = (name >> 8) & 0xff; \
> + c3 = name & 0xff; \
> + putchar( (isprint(c0)) ? c0 : '*' ); \
> + if ( c1 ) putchar( (isprint(c1)) ? c1 : '*' ); \
> + if ( c2 ) putchar( (isprint(c2)) ? c2 : '*' ); \
> + if ( c3 ) putchar( (isprint(c3)) ? c3 : '*' ); \
> + if ( crlf ) \
> + putchar( '\n' ); \
> +}
> +
> +#ifndef build_time
> +#define build_time( TB, MON, DAY, YR, HR, MIN, SEC, TK ) \
> + { (TB)->year = YR; \
> + (TB)->month = MON; \
> + (TB)->day = DAY; \
> + (TB)->hour = HR; \
> + (TB)->minute = MIN; \
> + (TB)->second = SEC; \
> + (TB)->ticks = TK; }
> +#endif
> +
> +#define task_number( tid ) \
> + ( rtems_object_id_get_index( tid ) - \
> + rtems_configuration_get_rtems_api_configuration()-> \
> + number_of_initialization_tasks )
> +
> +#define rtems_test_assert(__exp) \
> + do { \
> + if (!(__exp)) { \
> + printf( "%s: %d %s\n", __FILE__, __LINE__, #__exp ); \
> + rtems_test_exit(0); \
> + } \
> + } while (0)
> +
> +/*
> + * Various inttypes.h-stype macros to assist printing
> + * certain system types on different targets.
> + */
> +
> +#if defined(RTEMS_USE_16_BIT_OBJECT)
> +#define PRIxrtems_id PRIx16
> +#else
> +#define PRIxrtems_id PRIx32
> +#endif
> +
> +/* c.f. cpukit/score/include/rtems/score/priority.h */
> +#define PRIdPriority_Control PRId32
> +#define PRIxPriority_Control PRIx32
> +/* rtems_task_priority is a typedef to Priority_Control */
> +#define PRIdrtems_task_priority PRIdPriority_Control
> +#define PRIxrtems_task_priority PRIxPriority_Control
> +
> +/* c.f. cpukit/score/include/rtems/score/watchdog.h */
> +#define PRIdWatchdog_Interval PRIu32
> +/* rtems_interval is a typedef to Watchdog_Interval */
> +#define PRIdrtems_interval PRIdWatchdog_Interval
> +
> +/* c.f. cpukit/score/include/rtems/score/thread.h */
> +#define PRIdThread_Entry_numeric_type PRIuPTR
> +/* rtems_task_argument is a typedef to Thread_Entry_numeric_type */
> +#define PRIdrtems_task_argument PRIdThread_Entry_numeric_type
> +
> +/* rtems_event_set is a typedef to unit32_t */
> +#define PRIxrtems_event_set PRIx32
> +
> +/* HACK: newlib defines pthread_t as a typedef to __uint32_t */
> +/* HACK: There is no portable way to print pthread_t's */
> +#define PRIxpthread_t PRIx32
> +
> +/* rtems_signal_set is a typedef to uint32_t */
> +#define PRIxrtems_signal_set PRIx32
> +
> +/* newlib's ino_t is a typedef to "unsigned long" */
> +#define PRIxino_t "lx"
> +
> +/**
> + * This assists in clearly disabling warnings on GCC in certain very
> + * specific cases.
> + *
> + * + -Wnon-null - If a method is declared as never having a NULL first
> + * parameter. We need to explicitly disable this compiler warning to make
> + * the code warning free.
> + */
> +#ifdef __GNUC__
> + #define COMPILER_DIAGNOSTIC_SETTINGS_PUSH _Pragma("GCC diagnostic push")
> + #define COMPILER_DIAGNOSTIC_SETTINGS_POP _Pragma("GCC diagnostic pop")
> + #define COMPILER_DIAGNOSTIC_SETTINGS_DISABLE_NONNULL \
> + _Pragma("GCC diagnostic ignored \"-Wnonnull\"")
> +#else
> + #define COMPILER_DIAGNOSTIC_SETTINGS_PUSH
> + #define COMPILER_DIAGNOSTIC_SETTINGS_POP
> + #define COMPILER_DIAGNOSTIC_SETTINGS_DISABLE_NONNULL
> +#endif
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif
> --
> 1.8.4.5
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list