[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