changeset 46:c4e318929675

8057606: Expected UnavailableDeviceException is not thrown when again openning SPI in EXCLUSIVE mode Reviewed-by: jld Contributed-by: alexey.karaksin@oracle.com
author alkonsta
date Mon, 15 Sep 2014 18:00:42 +0400
parents 8472c11f06d8
children 27d423daf8ec
files src/share/linux/native/com/oracle/dio/spibus/spi.c
diffstat 1 files changed, 188 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/linux/native/com/oracle/dio/spibus/spi.c	Mon Sep 15 17:51:26 2014 +0400
+++ b/src/share/linux/native/com/oracle/dio/spibus/spi.c	Mon Sep 15 18:00:42 2014 +0400
@@ -33,6 +33,8 @@
 #include <linux/types.h>
 #include <linux/spi/spidev.h>
 #include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
 
 #define MAX(a,b)    ((a) > (b) ? (a) : (b))
 
@@ -56,43 +58,159 @@
     char* rxBuf;
 };
 
-typedef struct {
-    int busId;                       /* bus ID */
-    int address;                     /* chip enable:                */
+typedef struct _spi_slave_config spi_slave_config;
+
+struct _spi_slave_config{
+    int                busId;        /* bus ID */
+    int                address;      /* chip enable:                */
                                      /*    =  0 - NO_CS             */
                                      /*    =  1 - CE0/Pin8, CS_LOW  */
                                      /*    =  2 - CE1/Pin7, CS_LOW  */
                                      /*    = -1 - CE0/Pin8, CS_HIGH */
                                      /*    = -2 - CE1/Pin7, CS_HIGH */
-    int wordSize;                    /* word length in bits */
-    int clkFrequency;                /* clock frequency */
-    int clkMode;                     /* clock polarity & phase: */
+    int                wordSize;     /* word length in bits */
+    int                clkFrequency; /* clock frequency */
+    int                clkMode;      /* clock polarity & phase: */
                                      /* Mode CPOL CPHA */
                                      /*   0    0    0  */
                                      /*   1    0    1  */
                                      /*   2    1    0  */
                                      /*   3    1    1  */
     javacall_byteorder bitOrdering;  /* bit (shifting) ordering */
-    int devFd;
+    int                devFd;
     javacall_spi_cs_active csActive;
+    javacall_bool          busOwner;
+    spi_slave_config* next;
     spi_context* xfer_list;
-} spi_slave_config;
+};
 
-volatile javacall_handle spiOwner = NULL;
+#define SSC(arg) ((spi_slave_config*)arg)
 
-static javacall_dio_result spi_configure(const spi_slave_config* cfg);
-static void spi_disable(spi_slave_config* cfg);
-static javacall_dio_result spi_enable(spi_slave_config* cfg);
-static javacall_dio_result spi_transfer(const spi_slave_config* cfg, spi_context* data);
+static spi_slave_config* _spi_dev_list = NULL;
+static pthread_mutex_t _list_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static javacall_dio_result spi_configure (const spi_slave_config* cfg);
+static void            spi_disable   (spi_slave_config* cfg);
+static javacall_dio_result spi_enable    (spi_slave_config* cfg);
+static javacall_dio_result spi_transfer  (const spi_slave_config* cfg, spi_context* data);
+
+
+static spi_slave_config* get_opened_device(int bus_id, int address){
+    spi_slave_config* next = _spi_dev_list;
+
+    if(0 != pthread_mutex_lock(&_list_mutex)){
+        JAVACALL_REPORT_ERROR1(JC_DAAPI, "[SPI] get_opened_device: cannot lock mutex errno=%d\n", errno);
+        return NULL;
+    }
+
+    while (NULL != next) {
+        if (next->busId == bus_id && next->address == address) {
+            break;
+        }
+        next = next->next;
+    }
+
+    if(0 != pthread_mutex_unlock(&_list_mutex)){
+        JAVACALL_REPORT_WARN1(JC_DAAPI, "[SPI] get_opened_device: cannot unlock mutex errno=%d\n", errno);
+    }
+    return next;
+}
+
+static spi_slave_config* get_bus_owner(int bus_id){
+    spi_slave_config* next = _spi_dev_list;
+
+    if(0 != pthread_mutex_lock(&_list_mutex)){
+        JAVACALL_REPORT_ERROR1(JC_DAAPI, "[SPI] get_bus_owner: cannot lock mutex errno=%d\n", errno);
+        return NULL;
+    }
+
+    while (NULL != next) {
+        if (next->busId == bus_id && next->busOwner == JAVACALL_TRUE) {
+            break;
+        }
+        next = next->next;
+    }
+
+    if(0 != pthread_mutex_unlock(&_list_mutex)){
+        JAVACALL_REPORT_WARN1(JC_DAAPI, "[SPI] get_bus_owner: cannot unlock mutex errno=%d\n", errno);
+    }
+    return next;
+}
+
+
+/**
+ * Add spi config pointer to globl spi list
+ *
+ *@param spi_dev      pointer to spi device structure
+ *
+ *@retval JAVACALL_DIO_OK        on success
+ *@retval JAVACALL_DIO_FAIL      fail to get mutex, the device is NOT in the list
+ */
+static javacall_dio_result add_dev_to_list(spi_slave_config* spi_dev) {
+
+    if(0 != pthread_mutex_lock(&_list_mutex)){
+        JAVACALL_REPORT_ERROR1(JC_DAAPI, "[SPI] add_dev_to_list: cannot lock mutex errno=%d\n", errno);
+        return JAVACALL_DIO_FAIL;
+    }
+
+    spi_dev->next = _spi_dev_list;
+    _spi_dev_list = spi_dev;
+
+    if(0 != pthread_mutex_unlock(&_list_mutex)){
+        JAVACALL_REPORT_WARN1(JC_DAAPI, "[SPI] add_dev_to_list: cannot unlock mutex errno=%d\n", errno);
+    }
+
+    return JAVACALL_DIO_OK;
+}
+
+/**
+ * Remove spi config pointer to globl spi list
+ *
+ *@param spi_dev      pointer to spi device structure
+ *
+ *@retval JAVACALL_DIO_OK        on success
+ *@retval JAVACALL_DIO_FAIL      fail to get mutex, the device is NOT removed from the list
+ */
+static javacall_dio_result remove_dev_from_list(spi_slave_config* spi_dev) {
+
+    spi_slave_config* next;
+
+    if(0 != pthread_mutex_lock(&_list_mutex)){
+        JAVACALL_REPORT_ERROR1(JC_DAAPI, "[SPI] remove_dev_from_list: cannot lock mutex errno=%d\n", errno);
+        return JAVACALL_DIO_FAIL;
+    }
+
+    next = _spi_dev_list;
+
+    if(_spi_dev_list == NULL || _spi_dev_list == spi_dev){
+        //1 dev at the list
+        _spi_dev_list = NULL;
+    }else{
+        while (NULL != next->next){
+            if(spi_dev != next->next) {
+                next = next->next;
+            }else{
+                next->next = spi_dev->next;
+            }
+        }
+    }
+    if(0 != pthread_mutex_unlock(&_list_mutex)){
+        JAVACALL_REPORT_WARN1(JC_DAAPI, "[SPI] remove_dev_from_list: cannot unlock mutex errno=%d\n", errno);
+    }
+    return JAVACALL_DIO_OK;
+}
 
 /**
 * See javacall_spi.h for definition
 */
 javacall_dio_result javacall_spi_begin(javacall_handle handle) {
-    if (NULL != spiOwner) {
+    /*
+        check if other device own the bus
+    */
+    if (NULL != get_bus_owner(SSC(handle)->busId)) {
         return JAVACALL_DIO_INVALID_STATE;
     }
-    spiOwner = handle;
+    SSC(handle)->busOwner = JAVACALL_TRUE;
     return JAVACALL_DIO_OK;
 }
 
@@ -103,10 +221,10 @@
     javacall_dio_result res;
     spi_context* ctx;
     spi_slave_config* cfg = (spi_slave_config*)handle;
-    if (spiOwner != handle) {
+
+    if (SSC(handle)->busOwner != JAVACALL_TRUE) {
         return JAVACALL_DIO_INVALID_STATE;
     }
-    spiOwner = NULL;
 
     ctx = cfg->xfer_list;
     cfg->xfer_list = NULL;
@@ -117,6 +235,7 @@
         ctx = ctx->next;
         javacall_free(tmp);
     }
+    SSC(handle)->busOwner = JAVACALL_FALSE;
 
     return res;
 }
@@ -154,6 +273,10 @@
         return JAVACALL_DIO_UNSUPPORTED_ACCESS_MODE;
     }
 
+    if( NULL != get_opened_device(busId, address)){
+        return JAVACALL_DIO_BUSY;
+    }
+
     if (csActive == DAAPI_SPI_CS_DEFAULT) {
         csActive = DAAPI_SPI_CS_ACTIVE_LOW;
     }
@@ -179,12 +302,17 @@
 
     cfg->xfer_list = NULL;
 
+    cfg->busOwner = JAVACALL_FALSE;
+
     if ((res = spi_enable(cfg)) != JAVACALL_DIO_OK) {
-        javacall_free(cfg);
+        javacall_spi_close_slave(cfg);
         return res;
     }
 
-
+    if (JAVACALL_DIO_OK != add_dev_to_list(cfg)){
+        javacall_spi_close_slave(cfg);
+        return JAVACALL_DIO_FAIL;
+    }
     *pHandle = (javacall_handle)cfg;
     return JAVACALL_DIO_OK;
 }
@@ -193,8 +321,10 @@
 * See javacall_spi.h for definition
 */
 void javacall_spi_close_slave(javacall_handle handle) {
+
     spi_slave_config* cfg = (spi_slave_config*)handle;
     spi_disable(cfg);
+    remove_dev_from_list(cfg);
     javacall_free(cfg);
 }
 
@@ -215,7 +345,7 @@
     spi_context* context;
     spi_slave_config* cfg = (spi_slave_config*)handle;
 
-    if (spiOwner != NULL && spiOwner != handle) {
+    if ( (SSC(handle)->busOwner != JAVACALL_TRUE) && (get_bus_owner(SSC(handle)->busId) != NULL) ) {
         return JAVACALL_DIO_INVALID_STATE;
     }
 
@@ -228,7 +358,8 @@
         context->ref = 1;
         context->next = NULL;
 
-        if (NULL != spiOwner) {
+        if (SSC(handle)->busOwner == JAVACALL_TRUE) {
+            //the device is owner, a transaction has been started
             add_to_xfer_list(cfg, context);
         } else {
             res = spi_transfer(cfg, context);
@@ -272,25 +403,61 @@
 
 static javacall_dio_result spi_enable(spi_slave_config* cfg) {
     char device[32] = {0};
+    struct flock lock;
+    int res;
     sprintf(device, "/dev/spidev%d.%d",
             cfg->busId, cfg->address);
 
     cfg->devFd = open(device, O_RDWR | O_EXCL);
 
     if (0 <= cfg->devFd) {
+        lock.l_type   = F_WRLCK;  /* exclusive lock*/
+        lock.l_whence = SEEK_SET;
+        lock.l_start  = 0;
+        lock.l_len    = 0;
+        lock.l_pid    = getpid();
+
+        if(-1 == fcntl(cfg->devFd , F_SETLK, &lock)){
+            if (errno == EACCES || errno == EAGAIN) {
+                close(cfg->devFd);
+                cfg->devFd = -1;
+                return JAVACALL_DIO_BUSY;
+            }else{
+                JAVACALL_REPORT_ERROR1(JC_DAAPI, "[SPI] Can't lock device. errno %d", errno);
+                close(cfg->devFd);
+                cfg->devFd = -1;
+                return JAVACALL_DIO_FAIL;
+            }
+        }
         if (JAVACALL_DIO_OK != spi_configure(cfg)) {
             close(cfg->devFd);
             return JAVACALL_DIO_INVALID_CONFIG;
         }
         return JAVACALL_DIO_OK;
+    }else{
+        if(errno == EACCES){
+            JAVACALL_REPORT_ERROR1(JC_DAAPI, "[SPI] Can't open %s. Permission denied", device);
+        }
     }
 
     return JAVACALL_DIO_NOT_FOUND;
 }
 
 static void spi_disable(spi_slave_config* cfg) {
+    struct flock lock;
     if (cfg->devFd < 0)
         return;
+
+    lock.l_type   = F_UNLCK;
+    lock.l_whence = SEEK_SET;
+    lock.l_start  = 0;
+    lock.l_len    = 0;
+    lock.l_pid    = getpid();
+
+    if(-1 == fcntl(cfg->devFd , F_SETLK, &lock)){
+        JAVACALL_REPORT_ERROR1(JC_DAAPI, "[SPI] Can't unclock device. errno %d", errno);
+    }
+
     close( cfg->devFd );
     cfg->devFd = -1;
 }
@@ -385,4 +552,3 @@
     *grp =  'S' | 'P'<<8 | 'I'<<16 | spiSlave->busId << 24;
     return JAVACALL_DIO_OK;
 }
-