From 41c5f1b7795d95179d1b501fc93b27abd6c19d27 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 7 Nov 2014 13:47:39 +0100 Subject: Add I2C driver framework This I2C driver framework has some major differences compared to libi2c. * It is compatible to the Linux I2C user-space API. * It uses generic IMFS nodes and thus reduces the levels of indirection. * The drivers don't have to mess around with minor numbers to get their state information. * No arbitrary bus controller model is assumed. The main task of an I2C bus controller driver is to process I2C messages. How this is done is private to the driver. * Scatter/gather operations are supported (I2C_M_NOSTART). --- testsuites/libtests/i2c01/init.c | 286 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 testsuites/libtests/i2c01/init.c (limited to 'testsuites/libtests/i2c01/init.c') diff --git a/testsuites/libtests/i2c01/init.c b/testsuites/libtests/i2c01/init.c new file mode 100644 index 0000000000..7f38d34fc7 --- /dev/null +++ b/testsuites/libtests/i2c01/init.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tmacros.h" + +const char rtems_test_name[] = "I2C 1"; + +#define SPARE_ADDRESS_BITS 3 + +#define DEVICE_SIMPLE_READ_WRITE (0UL << SPARE_ADDRESS_BITS) + +typedef struct test_device test_device; + +struct test_device { + int (*transfer)( + i2c_bus *bus, + i2c_msg *msgs, + uint32_t msg_count, + test_device *dev + ); +}; + +typedef struct { + test_device base; + char buf[3]; +} test_device_simple_read_write; + +typedef struct { + i2c_bus base; + unsigned long clock; + test_device *devices[1]; + test_device_simple_read_write simple_read_write; +} test_bus; + +static const char bus_path[] = "/dev/i2c-0"; + +static int test_simple_read_write_transfer( + i2c_bus *bus, + i2c_msg *msgs, + uint32_t msg_count, + test_device *base +) +{ + 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].flags & I2C_M_RD) != 0) { + memcpy(msgs[0].buf, &dev->buf[0], sizeof(dev->buf)); + } else { + memcpy(&dev->buf[0], msgs[0].buf, sizeof(dev->buf)); + } + + return 0; + } else { + return -EIO; + } +} + +static int test_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count) +{ + test_bus *bus = (test_bus *) base; + uint16_t addr; + test_device *dev; + + addr = msgs[0].addr >> SPARE_ADDRESS_BITS; + if (addr >= RTEMS_ARRAY_SIZE(bus->devices)) { + return -EIO; + } + + dev = bus->devices[addr]; + + return (*dev->transfer)(&bus->base, msgs, msg_count, dev); +} + +static int test_set_clock(i2c_bus *base, unsigned long clock) +{ + test_bus *bus = (test_bus *) base; + + bus->clock = clock; + + return 0; +} + +static void test_destroy(i2c_bus *base) +{ + i2c_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; + + rv = ioctl(fd, I2C_SLAVE, DEVICE_SIMPLE_READ_WRITE); + rtems_test_assert(rv == 0); + + 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 *) i2c_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->base.functionality = I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING + | I2C_FUNC_NOSTART; + + bus->simple_read_write.base.transfer = test_simple_read_write_transfer; + bus->devices[0] = &bus->simple_read_write.base; + + rv = i2c_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, I2C_BUS_SET_CLOCK, 0xdeadbeefUL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->clock == 0xdeadbeef); + + rv = ioctl(fd, I2C_BUS_OBTAIN); + rtems_test_assert(rv == 0); + + rv = ioctl(fd, I2C_BUS_RELEASE); + rtems_test_assert(rv == 0); + + rtems_test_assert(!bus->base.ten_bit_address); + + rv = ioctl(fd, I2C_TENBIT, 1UL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->base.ten_bit_address); + + rv = ioctl(fd, I2C_TENBIT, 0UL); + rtems_test_assert(rv == 0); + rtems_test_assert(!bus->base.ten_bit_address); + + rtems_test_assert(!bus->base.use_pec); + + rv = ioctl(fd, I2C_PEC, 1UL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->base.use_pec); + + rv = ioctl(fd, I2C_PEC, 0UL); + rtems_test_assert(rv == 0); + rtems_test_assert(!bus->base.use_pec); + + rv = ioctl(fd, I2C_SLAVE, 123UL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->base.default_address == 123); + + rv = ioctl(fd, I2C_SLAVE_FORCE, 456UL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->base.default_address == 456); + + rtems_test_assert(bus->base.retries == 0); + + rv = ioctl(fd, I2C_RETRIES, 1UL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->base.retries == 1); + + rv = ioctl(fd, I2C_RETRIES, 0UL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->base.retries == 0); + + rtems_test_assert(bus->base.timeout == 0); + + rv = ioctl(fd, I2C_TIMEOUT, 1UL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->base.timeout == 5); + + rv = ioctl(fd, I2C_TIMEOUT, 0UL); + rtems_test_assert(rv == 0); + rtems_test_assert(bus->base.timeout == 0); + + 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) +{ + 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_USE_IMFS_AS_BASE_FILESYSTEM + +#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 -- cgit v1.2.3