This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 585c25bac0099367553a0c53ee5bbd011baf2b56
Author: Tiago Medicci Serrano <[email protected]>
AuthorDate: Mon Aug 25 14:34:22 2025 -0300

    drivers/i2s/i2schar: Implement blocking read/write operations
    
    This commit implements simple (blocking) read and write operations
    for the i2schar driver. Although it already contained such methods,
    the read/write operation was not being properly handled by the
    `i2schar_[rx|tx]callback` (called when the operation has finished).
    A semaphore is used to ensure that read data was received by the
    receiver and another semaphore ensures that data was written by the
    transmitter.
    
    Please note that the already-existing mutex for the I2S peripheral
    was replaced by two mutexes, one for the receiver and other for the
    transmitter to allow full-duplex communication.
    
    Signed-off-by: Tiago Medicci Serrano <[email protected]>
---
 drivers/i2s/i2schar.c | 72 +++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 59 insertions(+), 13 deletions(-)

diff --git a/drivers/i2s/i2schar.c b/drivers/i2s/i2schar.c
index b2fd7c3b60..b312f3640a 100644
--- a/drivers/i2s/i2schar.c
+++ b/drivers/i2s/i2schar.c
@@ -44,6 +44,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <errno.h>
+#include <semaphore.h>
 
 #include <nuttx/mutex.h>
 #include <nuttx/kmalloc.h>
@@ -76,7 +77,12 @@
 struct i2schar_dev_s
 {
   FAR struct i2s_dev_s *i2s;  /* The lower half i2s driver */
-  mutex_t lock;               /* Assures mutually exclusive access */
+  mutex_t rx_lock;            /* Assures mutually exclusive access to RX 
operations */
+  mutex_t tx_lock;            /* Assures mutually exclusive access to TX 
operations */
+  sem_t rx_sem;               /* Semaphore for blocking read operations */
+  sem_t tx_sem;               /* Semaphore for blocking write operations */
+  int rx_result;              /* Result of the last read operation */
+  int tx_result;              /* Result of the last write operation */
 };
 
 /****************************************************************************
@@ -156,10 +162,17 @@ static void i2schar_rxcallback(FAR struct i2s_dev_s *dev,
   FAR struct i2schar_dev_s *priv = (FAR struct i2schar_dev_s *)arg;
 
   DEBUGASSERT(priv != NULL && apb != NULL);
-  UNUSED(priv);
 
   i2sinfo("apb=%p nbytes=%d result=%d\n", apb, apb->nbytes, result);
 
+  /* Store the result and signal completion */
+
+  priv->rx_result = result;
+
+  /* Signal that the read operation has completed */
+
+  nxsem_post(&priv->rx_sem);
+
   /* REVISIT: If you want this to actually do something other than
    * test I2S data transfer, then this is the point where you would
    * want to pass the received I2S to some application.
@@ -206,10 +219,17 @@ static void i2schar_txcallback(FAR struct i2s_dev_s *dev,
   FAR struct i2schar_dev_s *priv = (FAR struct i2schar_dev_s *)arg;
 
   DEBUGASSERT(priv != NULL && apb != NULL);
-  UNUSED(priv);
 
   i2sinfo("apb=%p nbytes=%d result=%d\n", apb, apb->nbytes, result);
 
+  /* Store the result and signal completion */
+
+  priv->tx_result = result;
+
+  /* Signal that the write operation has completed */
+
+  nxsem_post(&priv->tx_sem);
+
   /* REVISIT: If you want this to actually do something other than
    * test I2S data transfer, then this is the point where you would
    * want to let some application know that the transfer has completed.
@@ -284,7 +304,7 @@ static ssize_t i2schar_read(FAR struct file *filep, FAR 
char *buffer,
 
   /* Get exclusive access to i2c character driver */
 
-  ret = nxmutex_lock(&priv->lock);
+  ret = nxmutex_lock(&priv->rx_lock);
   if (ret < 0)
     {
       i2serr("ERROR: nxsem_wait returned: %d\n", ret);
@@ -301,16 +321,34 @@ static ssize_t i2schar_read(FAR struct file *filep, FAR 
char *buffer,
       goto errout_with_reference;
     }
 
-  /* Lie to the caller and tell them that all of the bytes have been
-   * received
-   */
+  /* Wait for the RX callback to signal completion */
 
-  nxmutex_unlock(&priv->lock);
-  return sizeof(struct ap_buffer_s) + nbytes;
+  ret = nxsem_wait(&priv->rx_sem);
+  if (ret < 0)
+    {
+      i2serr("ERROR: nxsem_wait returned: %d\n", ret);
+      goto errout_with_reference;
+    }
+
+  /* Get the result from the private data */
+
+  ret = priv->rx_result;
+
+  /* If the operation was successful, return the number of bytes received */
+
+  if (ret >= 0)
+    {
+      ret = sizeof(struct ap_buffer_s) + apb->nbytes;
+    }
+
+  /* Release our reference to the audio buffer */
+
+  nxmutex_unlock(&priv->rx_lock);
+  return ret;
 
 errout_with_reference:
   apb_free(apb);
-  nxmutex_unlock(&priv->lock);
+  nxmutex_unlock(&priv->rx_lock);
   return ret;
 }
 
@@ -375,7 +413,7 @@ static ssize_t i2schar_write(FAR struct file *filep, FAR 
const char *buffer,
 
   /* Get exclusive access to i2c character driver */
 
-  ret = nxmutex_lock(&priv->lock);
+  ret = nxmutex_lock(&priv->tx_lock);
   if (ret < 0)
     {
       i2serr("ERROR: nxsem_wait returned: %d\n", ret);
@@ -595,7 +633,12 @@ int i2schar_register(FAR struct i2s_dev_s *i2s, int minor)
       /* Initialize the I2S character device structure */
 
       priv->i2s = i2s;
-      nxmutex_init(&priv->lock);
+      nxmutex_init(&priv->rx_lock);
+      nxmutex_init(&priv->tx_lock);
+      nxsem_init(&priv->rx_sem, 0, 0);
+      nxsem_init(&priv->tx_sem, 0, 0);
+      priv->rx_result = 0;
+      priv->tx_result = 0;
 
       /* Create the character device name */
 
@@ -607,7 +650,10 @@ int i2schar_register(FAR struct i2s_dev_s *i2s, int minor)
            * device.
            */
 
-          nxmutex_destroy(&priv->lock);
+          nxsem_destroy(&priv->tx_sem);
+          nxsem_destroy(&priv->rx_sem);
+          nxmutex_destroy(&priv->rx_lock);
+          nxmutex_destroy(&priv->tx_lock);
           kmm_free(priv);
           return ret;
         }

Reply via email to