view src/share/linux/native/com/oracle/dio/i2c/i2c.c @ 274:935bcaf28721

issue: https://bugs.openjdk.java.net/browse/DIO-21 Summary: Second call to DeviceManager.open() results in UDE, not IOE Reviewed-by:snazarki Contributed-by:bkvartsk
author onazarkina
date Wed, 30 Mar 2016 12:57:33 +0300
parents ad12ae44e850
children 2f7da76bdc69
line wrap: on
line source
/*
 * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <pthread.h>

#include "javacall_i2c.h"
#include "javacall_logging.h"
#include "javacall_memory.h"


#if ENABLE_DEBUG    
    #define BUS_WR_LOCK(bus) \
      JAVACALL_REPORT_ERROR3(JC_DIO, "going to wrlock on bus 0x%x (file %s, line %d) ", (bus),__FILE__,__LINE__); \
      pthread_rwlock_wrlock(&(bus)->lock); \
      JAVACALL_REPORT_ERROR3(JC_DIO, "set wrlock on bus 0x%x (file %s, line %d) ", (bus),__FILE__,__LINE__)

    #define BUS_RD_LOCK(bus) \
      JAVACALL_REPORT_ERROR3(JC_DIO, "going to rdlock on bus 0x%x (file %s, line %d) ", (bus),__FILE__,__LINE__); \
      pthread_rwlock_rdlock(&(bus)->lock); \
      JAVACALL_REPORT_ERROR3(JC_DIO, "set rdlock on bus 0x%x (file %s, line %d) ", (bus),__FILE__,__LINE__)

    #define BUS_UNLOCK(bus) \
      pthread_rwlock_unlock(&(bus)->lock); \
      JAVACALL_REPORT_ERROR3(JC_DIO, "unlocked bus 0x%x (file %s, line %d) ", (bus),__FILE__,__LINE__)

    #define BUSLIST_UNLOCK \
      pthread_rwlock_unlock(&_i2c_buses_lock); \
      JAVACALL_REPORT_ERROR2(JC_DIO, "unlocked bus list (file %s, line %d) ", __FILE__,__LINE__)

    #define BUSLIST_WR_LOCK \
      JAVACALL_REPORT_ERROR2(JC_DIO, "Going to wrlock bus list (file %s, line %d) ", __FILE__,__LINE__); \
      pthread_rwlock_wrlock(&_i2c_buses_lock); \
      JAVACALL_REPORT_ERROR2(JC_DIO, "Set wrlock on bus list (file %s, line %d) ", __FILE__,__LINE__)

    #define BUSLIST_RD_LOCK \
      JAVACALL_REPORT_ERROR2(JC_DIO, "Going to rdlock bus list (file %s, line %d) ", __FILE__,__LINE__); \
      pthread_rwlock_rdlock(&_i2c_buses_lock); \
      JAVACALL_REPORT_ERROR2(JC_DIO, "Set rdlock on bus list (file %s, line %d) ", __FILE__,__LINE__)
#else
    #define BUS_UNLOCK(bus) pthread_rwlock_unlock(&(bus)->lock)
    #define BUS_WR_LOCK(bus) pthread_rwlock_wrlock(&(bus)->lock)
    #define BUS_RD_LOCK(bus) pthread_rwlock_rdlock(&(bus)->lock)
    #define BUSLIST_UNLOCK pthread_rwlock_unlock(&_i2c_buses_lock)
    #define BUSLIST_WR_LOCK pthread_rwlock_wrlock(&_i2c_buses_lock)
    #define BUSLIST_RD_LOCK pthread_rwlock_rdlock(&_i2c_buses_lock)
#endif

enum {
    READ = 0,
    WRITE = 1
};

typedef struct {
    // I2C javacall handle to notify java thread
    javacall_handle pBus;
    javacall_handle pDev;
    struct i2c_rdwr_ioctl_data rdwr_data;
} i2c_io_context;

typedef struct i2c_bus_t i2c_bus;
typedef struct i2c_slave_str i2c_slave;
typedef struct i2c_frame_t i2c_frame;
typedef struct i2c_msg i2c_message;

struct i2c_bus_t {
    i2c_bus *next;
    unsigned int busId;
    //javacall_bool isBusy;
    //javacall_bool lastMessage;
    /* list of opened I2C slaves on the bus */
    i2c_slave *slaves;
    i2c_frame* currentTransaction;
    int fd;
    pthread_rwlock_t lock;
};

struct i2c_slave_str {
    long address;  /* 7 or 10 bits long */
    uint8_t addressSize;  /* 7 or 10 */
    long clockFrequency;
    pthread_t context;
    i2c_bus* bus;
    i2c_slave* next;
};

struct i2c_frame_t {
    i2c_frame* next;
    i2c_message msg;
};

/* global list of opened I2C buses */
static i2c_bus *_i2c_buses = NULL;
static pthread_rwlock_t _i2c_buses_lock = PTHREAD_RWLOCK_INITIALIZER;

static inline javacall_dio_result i2c_create_bus(unsigned int busId, i2c_bus** pBus) {
    i2c_bus *tmpBus;

    /* /dev/i2c-X file has been opened successfully,
     * created new 'i2c_bus' */
    tmpBus = (i2c_bus*) javacall_calloc(1, sizeof(i2c_bus));

    if (tmpBus == NULL ) {
        JAVACALL_REPORT_ERROR(JC_DIO, "[I2C] Memory allocation error, i2c_create_bus");
        return JAVACALL_DIO_OUT_OF_MEMORY;
    }

    tmpBus->busId = busId;
    tmpBus->slaves = NULL;
    tmpBus->currentTransaction = NULL;

    if (pthread_rwlock_init(&tmpBus->lock, NULL) != 0) {
        JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] Unable to create a rwlock for bus number %d", busId);
        javacall_free(tmpBus);
        return JAVACALL_DIO_FAIL;
    }

    /* Add newly created bus to 'g_i2c_buses' list */

    tmpBus->next = _i2c_buses;
    _i2c_buses = tmpBus;
    *pBus = tmpBus;

    return JAVACALL_DIO_OK;
}

/* find the bus with a given id or create one if it's not exist */
static inline javacall_dio_result i2c_get_bus(unsigned int busId, i2c_bus** pBus) {
    BUSLIST_WR_LOCK;
    i2c_bus *bus = _i2c_buses;

    while(bus) {
        if (bus->busId == busId) {
            *pBus = bus;
            BUSLIST_UNLOCK;
            return JAVACALL_DIO_OK;
        }
        bus = bus->next;
    }

    /* No currently opened i2c bus with 'busId' id. Create the new one */
    javacall_dio_result rv =  i2c_create_bus(busId, pBus);
    BUSLIST_UNLOCK;

    return rv;
}

static javacall_dio_result close_i2c_bus_file(i2c_bus * bus) {
   int rv;
   
   JAVACALL_REPORT_INFO1(JC_DIO, "[I2C] Closing bus file /dev/i2c-%d", bus->busId);
   /* If i2c device fd is opened */
    if (bus->fd >= 0) {
        /* close device fd */
        while ((rv = close(bus->fd)) < 0 && EINTR == errno);

        if (rv != 0)
            JAVACALL_REPORT_ERROR2(JC_DIO, "[I2C] Could not close bus file, errno=%d (%s)", errno, strerror(errno));
    }

    return (rv == 0)?
          JAVACALL_DIO_OK:
          JAVACALL_DIO_FAIL;
}

/* release bus if it has no opened slaves */
static javacall_dio_result i2c_release_bus(i2c_bus* bus) {
    i2c_bus *busPrev, *busCur;

    BUS_WR_LOCK(bus);

    if (NULL != bus->slaves) {
        JAVACALL_REPORT_INFO1(JC_DIO, "[I2C] There is no need to close bus file /dev/i2c-%d, there are open slaves in use", bus->busId);
        BUS_UNLOCK(bus);
        return JAVACALL_DIO_OK;
    }

    /* find the previous bus in the bus' list */
    BUSLIST_WR_LOCK;
    busPrev = NULL;
    busCur = _i2c_buses;

    while(busCur) {
        /* Check if it's a bus to remove */
        if (busCur == bus) {
            /* Check if it is about to remove first bus from the bus' list */
            if (NULL == busPrev) {
                _i2c_buses = bus->next;
            } else {
                busPrev->next = bus->next;
            }

            BUSLIST_UNLOCK;

            javacall_dio_result rv = close_i2c_bus_file(bus);
            BUS_UNLOCK(bus);

            if (pthread_rwlock_destroy(&bus->lock) != 0) {
                JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] unable to destroy bus access rwlock, bus id %d", bus->busId);
            }

            javacall_free(bus);
            return rv;
        }
        busPrev = busCur;
        busCur = busCur->next;
    }

    JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] inconsistency in bus list, failed to release %d", bus->busId);

    BUSLIST_UNLOCK;
    BUS_UNLOCK(bus);    
    return JAVACALL_DIO_FAIL;
}


static inline javacall_dio_result open_setup_i2c_bus_file(i2c_slave* slave, unsigned int busId) {
    if (slave->next != NULL)  {
        JAVACALL_REPORT_INFO1(JC_DIO, "[I2C] There is no need to open bus file /dev/i2c-%d, it is already open", busId);
    }

    JAVACALL_REPORT_INFO1(JC_DIO, "[I2C] Opening bus file /dev/i2c-%d", busId);
    char filename[20];

    snprintf(filename, 19, "/dev/i2c-%d", busId);
    restore_privileges();
    slave->bus->fd = open(filename, O_RDWR);
    drop_privileges();
   
    if (slave->bus->fd < 0) {
        JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] Could not open bus file %s ", filename);
        return JAVACALL_DIO_FAIL;
    }
    
    return JAVACALL_DIO_OK;
}


static inline javacall_dio_result i2c_attach_slave_to_bus(i2c_slave *slave, unsigned int busId) {
    javacall_dio_result rv;
    i2c_bus *bus;
    i2c_slave *tmpSlave;

    /* get bus descriptor */    
    rv = i2c_get_bus(busId, &bus);

    if (JAVACALL_DIO_OK != rv) {
        return rv;
    }

    BUS_WR_LOCK(bus);

    /* check if a slave with the same address is already opened */
    tmpSlave = bus->slaves;
    while (tmpSlave) {
        if (tmpSlave->address == slave->address) {
            BUS_UNLOCK(bus);
            return JAVACALL_DIO_BUSY;
        }
        tmpSlave = tmpSlave->next;
    }

    /* attach slave to the bus */
    slave->bus = bus;
    slave->next = bus->slaves;
    bus->slaves = slave;
    
    /*  open bus file is needed */
    javacall_dio_result ret =  open_setup_i2c_bus_file(slave, busId);
    BUS_UNLOCK(bus);
    return ret;
}

static inline javacall_dio_result i2c_detach_slave_from_bus(i2c_slave *slave) {
    i2c_slave *slavePrev, *slaveCur;

    /* find the previous slave in the slave's list */
    slavePrev = NULL;

    BUS_WR_LOCK(slave->bus);
    slaveCur = slave->bus->slaves;
    while(slaveCur) {
        if (slaveCur == slave) {
            break;
        }
        slavePrev = slaveCur;
        slaveCur = slaveCur->next;
    }

    /* Check if there are no given slave in the list */
    if (NULL == slaveCur) {
        JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] Inconsistency in the list of slaves, failed to release slave with address %d", slave->address);
        BUS_UNLOCK(slave->bus);
        return JAVACALL_DIO_FAIL;
    }

    /* Check if it is about to remove first slave from the slave's list */
    if (NULL == slavePrev) {
        slave->bus->slaves = slave->next;
        BUS_UNLOCK(slave->bus);
        i2c_release_bus(slave->bus);
    } else {
        /* There is at least one opened slave in the list before 'the slave to remove'.
           It means that there is not necessary to release bus struct. */
        slavePrev->next = slave->next;
        BUS_UNLOCK(slave->bus);
    }

    return JAVACALL_DIO_OK;
}


static void i2c_close_slave(i2c_slave *slave) {
    i2c_detach_slave_from_bus(slave);
    javacall_free(slave);
}


#if ENABLE_DEBUG    
static void dumpBuf(i2c_message* msg) {
    int i; 

    printf("[I2C] (address = 0x%X)", msg->addr);
    
    if (msg->flags & I2C_M_RD) {
        printf("--->");
    } else {
        printf("<---");
    }

    printf("[");

    for(i=0; i < msg->len - 1; i++) {
        printf("0x%X, ", msg->buf[i]);
    }

    if (msg->len > 0) {
       printf("0x%X", msg->buf[msg->len-1]);
    }

    printf("]\n");
}
#endif

javacall_dio_result javacall_i2c_open_slave_with_config(javacall_int32 busNum,
        javacall_int32 devAddr, javacall_int32 addrSize,
        javacall_int32 clockFrequency,
        const javacall_bool exclusive,
        /*OUT*/javacall_handle* pHandle) {
    javacall_dio_result ret;
    
    if (JAVACALL_TRUE != exclusive) {
        JAVACALL_REPORT_ERROR(JC_DIO, "[I2C] Shared mode is unsupported for I2C device");
        return JAVACALL_DIO_UNSUPPORTED_ACCESS_MODE;
    }
    
    if (clockFrequency != PERIPHERAL_CONFIG_DEFAULT) {
        JAVACALL_REPORT_ERROR(JC_DIO, "[I2C] Clock frequency == -1 is supported only.");
        return JAVACALL_DIO_INVALID_CONFIG;
    }
    
    if (addrSize == PERIPHERAL_CONFIG_DEFAULT)
        addrSize = 7;
    
    if (busNum == PERIPHERAL_CONFIG_DEFAULT)
        busNum = 1;
    
    if (addrSize != 7 && addrSize != 10) {
        JAVACALL_REPORT_ERROR(JC_DIO, "[I2C] Configuration error: addrSize != 7 or 10");
        return JAVACALL_DIO_INVALID_CONFIG;
    }
    
    if (busNum < 0) {
        JAVACALL_REPORT_ERROR(JC_DIO,
                "[I2C] Configuration error: busNum should not be less than zero");
        return JAVACALL_DIO_FAIL;
    }

    i2c_slave *slave;
    *pHandle = NULL;
   
    slave = (i2c_slave*) javacall_calloc(1, sizeof(i2c_slave));

    if (slave == NULL) {
        JAVACALL_REPORT_ERROR(JC_DIO,
                "[I2C] Memory allocation error, javacall_i2c_open_slave_with_config");
        return JAVACALL_DIO_OUT_OF_MEMORY;
    }
    
    
    slave->address = (long)devAddr;
    slave->addressSize = (long)addrSize;
    slave->clockFrequency = clockFrequency;
    
    /* Attach device to a bus */
    ret = i2c_attach_slave_to_bus(slave, busNum);
    if (JAVACALL_DIO_OK != ret) {
        if (slave->bus != NULL) {
            i2c_detach_slave_from_bus(slave);
        }

        /* dealloc descriptor */
        javacall_free(slave);
        return ret;
    }

    *pHandle = (javacall_handle) slave;

    return JAVACALL_DIO_OK;
}

void cleanupTransaction(i2c_bus *bus) {
    i2c_frame* transaction = bus->currentTransaction;
    i2c_frame* nextFrame = transaction;
    i2c_frame* curFrame = transaction;

    while(nextFrame != NULL) {
        curFrame=nextFrame;
        nextFrame = nextFrame->next;
        javacall_free(curFrame);
    }

    bus->currentTransaction = NULL;
}

static javacall_dio_result transaction_to_i2c_rdwr_ioctl_data(i2c_bus* bus, struct i2c_rdwr_ioctl_data* rdwr_data) {
    int transactionLength = 0;
    i2c_frame* nextFrame;
    i2c_frame* curFrame;
    int i;

    i2c_frame* transaction = bus->currentTransaction;
    
    if (transaction == NULL) {
        JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] Transaction is NULL for bus %d", bus->busId);
        return JAVACALL_DIO_FAIL;
    } else {
        nextFrame = transaction;
        
        while(nextFrame != NULL) {
            nextFrame = nextFrame->next; transactionLength++;
        }
    
        i2c_message* messages = (i2c_message*)javacall_malloc(sizeof(i2c_message)*transactionLength);

        if (messages == NULL) {
            JAVACALL_REPORT_ERROR(JC_DIO, "[I2C] Could not allocate memory for messages array");
            return JAVACALL_DIO_OUT_OF_MEMORY;
        } else {
           nextFrame = transaction;

           for(i = 0; i < transactionLength; i++) {
               *(messages + transactionLength - i - 1) = nextFrame->msg;
               nextFrame = nextFrame->next;
           }

           rdwr_data->msgs = messages;
           rdwr_data->nmsgs = transactionLength;
        }
    }
    return JAVACALL_DIO_OK;
}

static void* io_thread(void* arg) {
    i2c_io_context* ctx = (i2c_io_context*)arg;

    i2c_bus *pBus = (i2c_bus*)ctx->pBus;
    struct i2c_rdwr_ioctl_data* rdwr_data = &ctx->rdwr_data;
    int rv;

    int transactionLength = 0;
    i2c_frame* nextFrame;
    i2c_frame* curFrame;
    int i;
    
    rv=ioctl(pBus->fd, I2C_RDWR, rdwr_data);

#ifdef ENABLE_DEBUG
    for(i=0; i < rdwr_data->nmsgs; i++) {
        dumpBuf(rdwr_data->msgs + i);
    }
#endif
    
    if ( rv < 0 ) {
        JAVACALL_REPORT_ERROR2(JC_DIO, "[I2C] rdwr ioctl error: %d (%s)", errno, strerror(errno));
    } 

    if (rv >= 0) {
        rv = (rdwr_data->msgs + rdwr_data->nmsgs - 1)->len;
    }

    if (-1 == rv) {
        javanotify_i2c_event(JAVACALL_I2C_SEND_SIGNAL, ctx->pDev, JAVACALL_DIO_FAIL);
    } else {
        javanotify_i2c_event(JAVACALL_I2C_SEND_SIGNAL, ctx->pDev, JAVACALL_DIO_OK);
    }

    javacall_free(rdwr_data->msgs);
    javacall_free(ctx);

    return (void*)rv;
}

javacall_dio_result javacall_i2c_transfer_start(const javacall_handle handle,
                                                const javacall_i2c_message_type type,
                                                const javacall_bool write,
                                                char* pData, int len,
                                                javacall_int32 *const pBytes) {

    javacall_dio_result operationResult = JAVACALL_DIO_OK;
    i2c_slave* pDev = (i2c_slave*)handle;
        
    pthread_attr_t attr;
    
    if (JAVACALL_I2C_COMBINED_START == type || JAVACALL_I2C_REGULAR == type) {
        BUS_WR_LOCK(pDev->bus);
        if (NULL != pDev->bus->currentTransaction) {
            JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] Could not start transaction for bus id %d", pDev->bus->busId);
            BUS_UNLOCK(pDev->bus);
            return JAVACALL_DIO_INVALID_STATE;
        } else {
            JAVACALL_REPORT_INFO1(JC_DIO, "[I2C] Successfully started transaction for bus id %d", pDev->bus->busId);
        }
        BUS_UNLOCK(pDev->bus);
    }

    do {
        i2c_frame* nextFrame = (i2c_frame*) javacall_malloc(sizeof(i2c_frame));
    
        if (NULL == nextFrame) {
            JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] Could not allocate i2c message structure, errno=%d", errno);
            operationResult =  JAVACALL_DIO_OUT_OF_MEMORY;
            break;
        }
        
        nextFrame->msg.addr = pDev->address;
        nextFrame->msg.len = len;
        nextFrame->msg.buf = pData;
    
        if (write == JAVACALL_TRUE) {
           nextFrame->msg.flags = 0;
        } else {
           nextFrame->msg.flags = I2C_M_RD;
        }
    
        if (pDev->addressSize == 10) {
            nextFrame->msg.flags |= I2C_M_TEN;
        }
        
        nextFrame->next = pDev->bus->currentTransaction;
        pDev->bus->currentTransaction = nextFrame;
    
        if (JAVACALL_I2C_COMBINED_START == type || JAVACALL_I2C_COMBINED_BODY == type) {
            *pBytes = len;
            return JAVACALL_DIO_OK;
        }

        
        i2c_io_context *ctx = javacall_malloc(sizeof(i2c_io_context));
        
        if (NULL == ctx) {
            JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] Could not allocate temporary buffer, errno=%d", errno);
            operationResult =  JAVACALL_DIO_OUT_OF_MEMORY;
            break;
        }

        ctx->pDev = pDev;       
        ctx->pBus = pDev->bus;

        if (JAVACALL_DIO_OK != (operationResult = transaction_to_i2c_rdwr_ioctl_data(ctx->pBus, &ctx->rdwr_data))) {
            JAVACALL_REPORT_ERROR(JC_DIO, "[I2C] Failed to copy transaction to i2c_rdwr_ioctl_data structure");
            break;
        }

        if (pthread_create(&pDev->context, NULL, io_thread, ctx) != 0) {
            JAVACALL_REPORT_ERROR2(JC_DIO, "[I2C] failed to start i/o operation: errno=%d (%s)", errno, strerror(errno));
            javacall_free(ctx->rdwr_data.msgs);
            javacall_free(ctx);
            operationResult =  JAVACALL_DIO_FAIL;
            break;
        }
    } while (0);
    
    if (operationResult != JAVACALL_DIO_OK) {
        BUS_WR_LOCK(pDev->bus);
        cleanupTransaction(pDev->bus);        
        BUS_UNLOCK(pDev->bus);
        return operationResult;
    } 

    return JAVACALL_DIO_WOULD_BLOCK;
}

javacall_dio_result javacall_i2c_transfer_finish(const javacall_handle handle,
                                                 const javacall_bool cancel,
                                                 char* pData, int len,
                                                 javacall_int32* const pBytes) {
    i2c_slave* pDev = (i2c_slave*)handle;

    BUS_WR_LOCK(pDev->bus);
    cleanupTransaction(pDev->bus);        
    BUS_UNLOCK(pDev->bus);
    
    if (cancel == JAVACALL_TRUE) {
        if (pDev->context != NULL) {
            pthread_detach(pDev->context);
        }
    } else {
        if (0 != pthread_join(pDev->context, (void**)pBytes)) {
            JAVACALL_REPORT_ERROR1(JC_DIO, "[I2C] Could not join io_thread: %d", errno);
            return JAVACALL_DIO_FAIL;
        }
    }

    return JAVACALL_DIO_OK;
}


/**
 * See javacall_i2c.h for definition
 */
void javacall_i2c_close(javacall_handle handle) {
    i2c_close_slave((i2c_slave*)handle);
}

/**
 * See javacall_i2c.h for definition
 */
javacall_dio_result javacall_i2c_get_group_id(const javacall_handle handle,
        /*OUT*/ int* grpId) {
    i2c_slave *pDev = (i2c_slave*)handle;
    *grpId = (int)pDev->bus;
    return JAVACALL_DIO_OK;
}

/**
 * See javacall_i2c.h for definition
 */
javacall_dio_result javacall_i2c_lock(const javacall_handle handle, javacall_handle* const owner) {
    (void)handle;
    (void)owner;
    // exclusive mode only
    return JAVACALL_DIO_OK;
}

/**
 * See javacall_i2c.h for definition
 */
javacall_dio_result javacall_i2c_unlock(const javacall_handle handle) {
    (void)handle;
    // exclusive mode only
    return JAVACALL_DIO_OK;
}