Changeset 5bb5e01 in rtems


Ignore:
Timestamp:
May 26, 2021, 2:33:40 PM (2 months ago)
Author:
Christian Mauderer <christian.mauderer@…>
Branches:
master
Children:
a0a8262
Parents:
b47dbbc5
git-author:
Christian Mauderer <christian.mauderer@…> (05/26/21 14:33:40)
git-committer:
Christian Mauderer <christian.mauderer@…> (06/22/21 11:51:17)
Message:

i2c: Add non blocking read / write

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.

Files:
3 edited

Legend:

Unmodified
Added
Removed
  • cpukit/dev/i2c/i2c-bus.c

    rb47dbbc5 r5bb5e01  
    3232#include <string.h>
    3333
     34int i2c_bus_try_obtain(i2c_bus *bus)
     35{
     36  return rtems_recursive_mutex_try_lock(&bus->mutex);
     37}
     38
    3439void i2c_bus_obtain(i2c_bus *bus)
    3540{
     
    4247}
    4348
    44 int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count)
     49int i2c_bus_do_transfer(
     50  i2c_bus *bus,
     51  i2c_msg *msgs,
     52  uint32_t msg_count,
     53  uint32_t flags
     54)
    4555{
    4656  int err;
     
    6474  }
    6575
    66   i2c_bus_obtain(bus);
     76  if ((flags & I2C_BUS_NOBLOCK) != 0) {
     77    if (i2c_bus_try_obtain(bus) != 0) {
     78      return -EAGAIN;
     79    }
     80  } else {
     81    i2c_bus_obtain(bus);
     82  }
    6783  err = (*bus->transfer)(bus, msgs, msg_count);
    6884  i2c_bus_release(bus);
    6985
    7086  return err;
     87}
     88
     89int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count)
     90{
     91  return i2c_bus_do_transfer(bus, msgs, msg_count, 0);
    7192}
    7293
     
    85106  };
    86107  int err;
     108  unsigned flags = 0;
    87109
    88110  if (bus->ten_bit_address) {
     
    90112  }
    91113
    92   err = i2c_bus_transfer(bus, &msg, 1);
     114  if (rtems_libio_iop_is_no_delay(iop)) {
     115    flags |= I2C_BUS_NOBLOCK;
     116  }
     117
     118  err = i2c_bus_do_transfer(bus, &msg, 1, flags);
    93119  if (err == 0) {
    94120    return msg.len;
     
    112138  };
    113139  int err;
     140  unsigned flags = 0;
    114141
    115142  if (bus->ten_bit_address) {
     
    117144  }
    118145
    119   err = i2c_bus_transfer(bus, &msg, 1);
     146  if (rtems_libio_iop_is_no_delay(iop)) {
     147    flags |= I2C_BUS_NOBLOCK;
     148  }
     149
     150  err = i2c_bus_do_transfer(bus, &msg, 1, flags);
    120151  if (err == 0) {
    121152    return msg.len;
     
    134165  i2c_rdwr_ioctl_data *rdwr;
    135166  int err;
     167  unsigned flags = 0;
    136168
    137169  switch (command) {
     
    139171      rdwr = arg;
    140172      if (rdwr->nmsgs > 0) {
    141         err = i2c_bus_transfer(bus, rdwr->msgs, rdwr->nmsgs);
     173        if (rtems_libio_iop_is_no_delay(iop)) {
     174          flags |= I2C_BUS_NOBLOCK;
     175        }
     176        err = i2c_bus_do_transfer(bus, rdwr->msgs, rdwr->nmsgs, flags);
    142177      } else {
    143178        err = 0;
  • cpukit/include/dev/i2c/i2c.h

    rb47dbbc5 r5bb5e01  
    244244
    245245/**
     246 * @brief Try to obtain the bus.
     247 *
     248 * @param[in] bus The bus control.
     249 *
     250 * @retval 0 Successful operation.
     251 * @retval EBUSY if mutex is already locked.
     252 */
     253int i2c_bus_try_obtain(i2c_bus *bus);
     254
     255/**
    246256 * @brief Obtains the bus.
    247257 *
     
    260270 * @brief Transfers I2C messages.
    261271 *
    262  * The bus is obtained before the transfer and released afterwards.
     272 * The bus is obtained before the transfer and released afterwards. This is the
     273 * same like calling @ref i2c_bus_do_transfer with flags set to 0.
    263274 *
    264275 * @param[in] bus The bus control.
     
    271282 */
    272283int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count);
     284
     285/**
     286 * @brief Transfers I2C messages with optional flags.
     287 *
     288 * The bus is obtained before the transfer and released afterwards. If the flag
     289 * I2C_BUS_NOBLOCK is set and the bus is already obtained, nothing will be
     290 * transfered and the function returns with an -EAGAIN.
     291 *
     292 * @param[in] bus The bus control.
     293 * @param[in] msgs The messages to transfer.
     294 * @param[in] msg_count The count of messages to transfer.  It must be
     295 * positive.
     296 * @param[in] flags Options for the whole transfer.
     297 *
     298 * @retval 0 Successful operation.
     299 * @retval -EAGAIN if @ref I2C_BUS_NOBLOCK is set and the bus is already
     300 * obtained.
     301 * @retval negative Negative error number in case of an error.
     302 */
     303int i2c_bus_do_transfer(
     304  i2c_bus *bus,
     305  i2c_msg *msgs,
     306  uint32_t msg_count,
     307  uint32_t flags
     308);
     309
     310/**
     311 * @brief I2C bus transfer flag to indicate that the task should not block if
     312 * the bus is busy on a new transfer.
     313 */
     314#define I2C_BUS_NOBLOCK (1u << 0)
    273315
    274316/** @} */
  • testsuites/libtests/i2c01/init.c

    rb47dbbc5 r5bb5e01  
    337337}
    338338
     339typedef struct {
     340  rtems_id caller;
     341  int fd;
     342} bus_obtainer_ctx;
     343
     344static void bus_obtainer_task(rtems_task_argument arg)
     345{
     346  rtems_event_set e = 0;
     347  bus_obtainer_ctx *c = (bus_obtainer_ctx *) arg;
     348  int rv;
     349  rtems_status_code sc;
     350
     351  rv = ioctl(c->fd, I2C_BUS_OBTAIN);
     352  rtems_test_assert(rv == 0);
     353
     354  sc = rtems_event_send(c->caller, RTEMS_EVENT_1);
     355  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     356  sc = rtems_event_receive(
     357    RTEMS_EVENT_1,
     358    RTEMS_EVENT_ANY | RTEMS_WAIT,
     359    100,
     360    &e
     361  );
     362  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     363
     364  rv = ioctl(c->fd, I2C_BUS_RELEASE);
     365  rtems_test_assert(rv == 0);
     366
     367  sc = rtems_event_send(c->caller, RTEMS_EVENT_1);
     368  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     369}
     370
     371static void test_nonblock_read_write(test_bus *bus, int fd)
     372{
     373  int flags;
     374  int rv;
     375  char buf[3];
     376  ssize_t n;
     377  i2c_msg msgs[] = {{
     378    .addr = 1,
     379    .flags = I2C_M_STOP,
     380    .len = sizeof(buf),
     381    .buf = (uint8_t *) buf,
     382  }};
     383  struct i2c_rdwr_ioctl_data payload = {
     384    .msgs = msgs,
     385    .nmsgs = sizeof(msgs)/sizeof(msgs[0]),
     386  };
     387  rtems_id id;
     388  rtems_event_set e = 0;
     389  bus_obtainer_ctx ctx = {
     390    .caller = rtems_task_self(),
     391    .fd = fd,
     392  };
     393  rtems_status_code sc;
     394
     395  flags = fcntl(fd, F_GETFL, 0);
     396  rtems_test_assert(flags > 0);
     397
     398  rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
     399  rtems_test_assert(rv != -1);
     400
     401  sc = rtems_task_create(
     402    rtems_build_name('O', 'B', 'T', 'A'),
     403    2,
     404    RTEMS_MINIMUM_STACK_SIZE,
     405    RTEMS_DEFAULT_MODES,
     406    RTEMS_DEFAULT_ATTRIBUTES,
     407    &id
     408  );
     409  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     410
     411  sc = rtems_task_start(
     412    id,
     413    bus_obtainer_task,
     414    (rtems_task_argument) &ctx
     415  );
     416  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     417
     418  sc = rtems_event_receive(
     419    RTEMS_EVENT_1,
     420    RTEMS_EVENT_ANY | RTEMS_WAIT,
     421    100,
     422    &e
     423  );
     424  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     425
     426  errno = 0;
     427  n = read(fd, &buf[0], sizeof(buf));
     428  rtems_test_assert(n == -1);
     429  rtems_test_assert(errno == EAGAIN);
     430
     431  errno = 0;
     432  n = write(fd, &buf[0], sizeof(buf));
     433  rtems_test_assert(n == -1);
     434  rtems_test_assert(errno == EAGAIN);
     435
     436  errno = 0;
     437  rv = ioctl(fd, I2C_RDWR, &payload);
     438  rtems_test_assert(rv == -1);
     439  rtems_test_assert(errno == EAGAIN);
     440
     441  sc = rtems_event_send(id, RTEMS_EVENT_1);
     442  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     443  sc = rtems_event_receive(
     444    RTEMS_EVENT_1,
     445    RTEMS_EVENT_ANY | RTEMS_WAIT,
     446    100,
     447    &e
     448  );
     449  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     450  sc = rtems_task_delete(id);
     451  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     452
     453  rv = fcntl(fd, F_SETFL, flags);
     454  rtems_test_assert(rv != -1);
     455}
     456
    339457static void test_gpio_nxp_pca9535(void)
    340458{
     
    628746
    629747  test_simple_read_write(bus, fd);
     748  test_nonblock_read_write(bus, fd);
    630749  test_eeprom(bus);
    631750  test_gpio_nxp_pca9535();
     
    658777#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 7
    659778
    660 #define CONFIGURE_MAXIMUM_TASKS 1
     779#define CONFIGURE_MAXIMUM_TASKS 2
    661780
    662781#define CONFIGURE_MAXIMUM_SEMAPHORES 1
Note: See TracChangeset for help on using the changeset viewer.