it looks ok
On Mon, Jun 21, 2021 at 8:08 AM Christian MAUDERER <christian.maude...@embedded-brains.de> wrote: > > Ping. > > Am 26.05.21 um 16:39 schrieb Christian Mauderer: > > This adds the possibility to open an I2C bus with O_NONBLOCK (or set it > > later via fcntl) to get non-blocking transmissions. This means that if > > the bus is busy, a read, write or transfer ioctl will return with a > > EAGAIN errno. > > --- > > NOTE: This patch needs > > https://lists.rtems.org/pipermail/devel/2021-May/067462.html applied too. > > > > cpukit/dev/i2c/i2c-bus.c | 45 ++++++++++-- > > cpukit/include/dev/i2c/i2c.h | 44 ++++++++++- > > testsuites/libtests/i2c01/init.c | 121 ++++++++++++++++++++++++++++++- > > 3 files changed, 203 insertions(+), 7 deletions(-) > > > > diff --git a/cpukit/dev/i2c/i2c-bus.c b/cpukit/dev/i2c/i2c-bus.c > > index 472222c4ab..618a817b1a 100644 > > --- a/cpukit/dev/i2c/i2c-bus.c > > +++ b/cpukit/dev/i2c/i2c-bus.c > > @@ -31,6 +31,11 @@ > > #include <stdlib.h> > > #include <string.h> > > > > +int i2c_bus_try_obtain(i2c_bus *bus) > > +{ > > + return rtems_recursive_mutex_try_lock(&bus->mutex); > > +} > > + > > void i2c_bus_obtain(i2c_bus *bus) > > { > > rtems_recursive_mutex_lock(&bus->mutex); > > @@ -41,7 +46,12 @@ void i2c_bus_release(i2c_bus *bus) > > rtems_recursive_mutex_unlock(&bus->mutex); > > } > > > > -int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count) > > +int i2c_bus_do_transfer( > > + i2c_bus *bus, > > + i2c_msg *msgs, > > + uint32_t msg_count, > > + uint32_t flags > > +) > > { > > int err; > > uint32_t i; > > @@ -63,13 +73,24 @@ int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, > > uint32_t msg_count) > > } > > } > > > > - i2c_bus_obtain(bus); > > + if ((flags & I2C_BUS_NOBLOCK) != 0) { > > + if (i2c_bus_try_obtain(bus) != 0) { > > + return -EAGAIN; > > + } > > + } else { > > + i2c_bus_obtain(bus); > > + } > > err = (*bus->transfer)(bus, msgs, msg_count); > > i2c_bus_release(bus); > > > > return err; > > } > > > > +int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count) > > +{ > > + return i2c_bus_do_transfer(bus, msgs, msg_count, 0); > > +} > > + > > static ssize_t i2c_bus_read( > > rtems_libio_t *iop, > > void *buffer, > > @@ -84,12 +105,17 @@ static ssize_t i2c_bus_read( > > .buf = buffer > > }; > > int err; > > + unsigned flags = 0; > > > > if (bus->ten_bit_address) { > > msg.flags |= I2C_M_TEN; > > } > > > > - err = i2c_bus_transfer(bus, &msg, 1); > > + if (rtems_libio_iop_is_no_delay(iop)) { > > + flags |= I2C_BUS_NOBLOCK; > > + } > > + > > + err = i2c_bus_do_transfer(bus, &msg, 1, flags); > > if (err == 0) { > > return msg.len; > > } else { > > @@ -111,12 +137,17 @@ static ssize_t i2c_bus_write( > > .buf = RTEMS_DECONST(void *, buffer) > > }; > > int err; > > + unsigned flags = 0; > > > > if (bus->ten_bit_address) { > > msg.flags |= I2C_M_TEN; > > } > > > > - err = i2c_bus_transfer(bus, &msg, 1); > > + if (rtems_libio_iop_is_no_delay(iop)) { > > + flags |= I2C_BUS_NOBLOCK; > > + } > > + > > + err = i2c_bus_do_transfer(bus, &msg, 1, flags); > > if (err == 0) { > > return msg.len; > > } else { > > @@ -133,12 +164,16 @@ static int i2c_bus_ioctl( > > i2c_bus *bus = IMFS_generic_get_context_by_iop(iop); > > i2c_rdwr_ioctl_data *rdwr; > > int err; > > + unsigned flags = 0; > > > > switch (command) { > > case I2C_RDWR: > > rdwr = arg; > > if (rdwr->nmsgs > 0) { > > - err = i2c_bus_transfer(bus, rdwr->msgs, rdwr->nmsgs); > > + if (rtems_libio_iop_is_no_delay(iop)) { > > + flags |= I2C_BUS_NOBLOCK; > > + } > > + err = i2c_bus_do_transfer(bus, rdwr->msgs, rdwr->nmsgs, flags); > > } else { > > err = 0; > > } > > diff --git a/cpukit/include/dev/i2c/i2c.h b/cpukit/include/dev/i2c/i2c.h > > index ac2c369785..5aa45e390c 100644 > > --- a/cpukit/include/dev/i2c/i2c.h > > +++ b/cpukit/include/dev/i2c/i2c.h > > @@ -242,6 +242,16 @@ int i2c_bus_register( > > const char *bus_path > > ); > > > > +/** > > + * @brief Try to obtain the bus. > > + * > > + * @param[in] bus The bus control. > > + * > > + * @retval 0 Successful operation. > > + * @retval EBUSY if mutex is already locked. > > + */ > > +int i2c_bus_try_obtain(i2c_bus *bus); > > + > > /** > > * @brief Obtains the bus. > > * > > @@ -259,7 +269,8 @@ void i2c_bus_release(i2c_bus *bus); > > /** > > * @brief Transfers I2C messages. > > * > > - * The bus is obtained before the transfer and released afterwards. > > + * The bus is obtained before the transfer and released afterwards. This > > is the > > + * same like calling @ref i2c_bus_do_transfer with flags set to 0. > > * > > * @param[in] bus The bus control. > > * @param[in] msgs The messages to transfer. > > @@ -271,6 +282,37 @@ void i2c_bus_release(i2c_bus *bus); > > */ > > int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count); > > > > +/** > > + * @brief Transfers I2C messages with optional flags. > > + * > > + * The bus is obtained before the transfer and released afterwards. If the > > flag > > + * I2C_BUS_NOBLOCK is set and the bus is already obtained, nothing will be > > + * transfered and the function returns with an -EAGAIN. > > + * > > + * @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. > > + * @param[in] flags Options for the whole transfer. > > + * > > + * @retval 0 Successful operation. > > + * @retval -EAGAIN if @ref I2C_BUS_NOBLOCK is set and the bus is already > > + * obtained. > > + * @retval negative Negative error number in case of an error. > > + */ > > +int i2c_bus_do_transfer( > > + i2c_bus *bus, > > + i2c_msg *msgs, > > + uint32_t msg_count, > > + uint32_t flags > > +); > > + > > +/** > > + * @brief I2C bus transfer flag to indicate that the task should not block > > if > > + * the bus is busy on a new transfer. > > + */ > > +#define I2C_BUS_NOBLOCK (1u << 0) > > + > > /** @} */ > > > > /** > > diff --git a/testsuites/libtests/i2c01/init.c > > b/testsuites/libtests/i2c01/init.c > > index 83027ed548..c71b78c275 100644 > > --- a/testsuites/libtests/i2c01/init.c > > +++ b/testsuites/libtests/i2c01/init.c > > @@ -336,6 +336,124 @@ static void test_simple_read_write(test_bus *bus, int > > fd) > > rtems_test_assert(memcmp(&buf[0], &abc[0], sizeof(buf)) == 0); > > } > > > > +typedef struct { > > + rtems_id caller; > > + int fd; > > +} bus_obtainer_ctx; > > + > > +static void bus_obtainer_task(rtems_task_argument arg) > > +{ > > + rtems_event_set e = 0; > > + bus_obtainer_ctx *c = (bus_obtainer_ctx *) arg; > > + int rv; > > + rtems_status_code sc; > > + > > + rv = ioctl(c->fd, I2C_BUS_OBTAIN); > > + rtems_test_assert(rv == 0); > > + > > + sc = rtems_event_send(c->caller, RTEMS_EVENT_1); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > + sc = rtems_event_receive( > > + RTEMS_EVENT_1, > > + RTEMS_EVENT_ANY | RTEMS_WAIT, > > + 100, > > + &e > > + ); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > + > > + rv = ioctl(c->fd, I2C_BUS_RELEASE); > > + rtems_test_assert(rv == 0); > > + > > + sc = rtems_event_send(c->caller, RTEMS_EVENT_1); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > +} > > + > > +static void test_nonblock_read_write(test_bus *bus, int fd) > > +{ > > + int flags; > > + int rv; > > + char buf[3]; > > + ssize_t n; > > + i2c_msg msgs[] = {{ > > + .addr = 1, > > + .flags = I2C_M_STOP, > > + .len = sizeof(buf), > > + .buf = (uint8_t *) buf, > > + }}; > > + struct i2c_rdwr_ioctl_data payload = { > > + .msgs = msgs, > > + .nmsgs = sizeof(msgs)/sizeof(msgs[0]), > > + }; > > + rtems_id id; > > + rtems_event_set e = 0; > > + bus_obtainer_ctx ctx = { > > + .caller = rtems_task_self(), > > + .fd = fd, > > + }; > > + rtems_status_code sc; > > + > > + flags = fcntl(fd, F_GETFL, 0); > > + rtems_test_assert(flags > 0); > > + > > + rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK); > > + rtems_test_assert(rv != -1); > > + > > + sc = rtems_task_create( > > + rtems_build_name('O', 'B', 'T', 'A'), > > + 2, > > + RTEMS_MINIMUM_STACK_SIZE, > > + RTEMS_DEFAULT_MODES, > > + RTEMS_DEFAULT_ATTRIBUTES, > > + &id > > + ); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > + > > + sc = rtems_task_start( > > + id, > > + bus_obtainer_task, > > + (rtems_task_argument) &ctx > > + ); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > + > > + sc = rtems_event_receive( > > + RTEMS_EVENT_1, > > + RTEMS_EVENT_ANY | RTEMS_WAIT, > > + 100, > > + &e > > + ); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > + > > + errno = 0; > > + n = read(fd, &buf[0], sizeof(buf)); > > + rtems_test_assert(n == -1); > > + rtems_test_assert(errno == EAGAIN); > > + > > + errno = 0; > > + n = write(fd, &buf[0], sizeof(buf)); > > + rtems_test_assert(n == -1); > > + rtems_test_assert(errno == EAGAIN); > > + > > + errno = 0; > > + rv = ioctl(fd, I2C_RDWR, &payload); > > + rtems_test_assert(rv == -1); > > + rtems_test_assert(errno == EAGAIN); > > + > > + sc = rtems_event_send(id, RTEMS_EVENT_1); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > + sc = rtems_event_receive( > > + RTEMS_EVENT_1, > > + RTEMS_EVENT_ANY | RTEMS_WAIT, > > + 100, > > + &e > > + ); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > + sc = rtems_task_delete(id); > > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > > + > > + rv = fcntl(fd, F_SETFL, flags); > > + rtems_test_assert(rv != -1); > > +} > > + > > static void test_gpio_nxp_pca9535(void) > > { > > int rv; > > @@ -627,6 +745,7 @@ static void test(void) > > rtems_test_assert(bus->base.timeout == 0); > > > > test_simple_read_write(bus, fd); > > + test_nonblock_read_write(bus, fd); > > test_eeprom(bus); > > test_gpio_nxp_pca9535(); > > test_switch_nxp_pca9548a(); > > @@ -657,7 +776,7 @@ static void Init(rtems_task_argument arg) > > > > #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 7 > > > > -#define CONFIGURE_MAXIMUM_TASKS 1 > > +#define CONFIGURE_MAXIMUM_TASKS 2 > > > > #define CONFIGURE_MAXIMUM_SEMAPHORES 1 > > > > > > -- > -------------------------------------------- > embedded brains GmbH > Herr Christian MAUDERER > Dornierstr. 4 > 82178 Puchheim > Germany > email: christian.maude...@embedded-brains.de > phone: +49-89-18 94 741 - 18 > fax: +49-89-18 94 741 - 08 > > Registergericht: Amtsgericht München > Registernummer: HRB 157899 > Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler > Unsere Datenschutzerklärung finden Sie hier: > https://embedded-brains.de/datenschutzerklaerung/ > _______________________________________________ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel