You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/07/29 15:11:39 UTC

[incubator-nuttx] 01/02: drivers/ipcc: add Inter Processor Communication driver

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/incubator-nuttx.git

commit a9f78a64db9d51614d87821d5159fe95a1cbeb02
Author: Michał Łyszczek <mi...@bofc.pl>
AuthorDate: Tue Jun 28 15:45:41 2022 +0200

    drivers/ipcc: add Inter Processor Communication driver
    
    This patch adds upper half driver for IPCC character driver. IPCC
    is a Inter Processor Communication Controller.
    
    Driver is still immature and not thoroughly tested, thus
    CONFIG_EXPERIMENTAL is required.
    
    Signed-off-by: Michał Łyszczek <mi...@bofc.pl>
---
 drivers/Kconfig              |   1 +
 drivers/Makefile             |   1 +
 drivers/ipcc/Kconfig         |  33 ++++++
 drivers/ipcc/Make.defs       |  41 +++++++
 drivers/ipcc/ipcc_close.c    |  94 ++++++++++++++++
 drivers/ipcc/ipcc_open.c     |  80 ++++++++++++++
 drivers/ipcc/ipcc_poll.c     | 203 ++++++++++++++++++++++++++++++++++
 drivers/ipcc/ipcc_priv.h     |  63 +++++++++++
 drivers/ipcc/ipcc_read.c     | 232 +++++++++++++++++++++++++++++++++++++++
 drivers/ipcc/ipcc_register.c | 189 ++++++++++++++++++++++++++++++++
 drivers/ipcc/ipcc_unlink.c   |  96 ++++++++++++++++
 drivers/ipcc/ipcc_write.c    | 256 +++++++++++++++++++++++++++++++++++++++++++
 include/nuttx/ipcc.h         | 204 ++++++++++++++++++++++++++++++++++
 13 files changed, 1493 insertions(+)

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 8a9d162ed6..7bf009d10d 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -14,6 +14,7 @@ source "drivers/clk/Kconfig"
 source "drivers/i2c/Kconfig"
 source "drivers/spi/Kconfig"
 source "drivers/i2s/Kconfig"
+source "drivers/ipcc/Kconfig"
 source "drivers/timers/Kconfig"
 source "drivers/analog/Kconfig"
 source "drivers/audio/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index bfe6cf15f8..e2e0218490 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -36,6 +36,7 @@ include math/Make.defs
 include motor/Make.defs
 include i2c/Make.defs
 include i2s/Make.defs
+include ipcc/Make.defs
 include input/Make.defs
 include ioexpander/Make.defs
 include lcd/Make.defs
diff --git a/drivers/ipcc/Kconfig b/drivers/ipcc/Kconfig
new file mode 100644
index 0000000000..1dbd87c330
--- /dev/null
+++ b/drivers/ipcc/Kconfig
@@ -0,0 +1,33 @@
+menuconfig IPCC
+	bool "IPCC (Inter Processor Communication Controller) driver"
+	select MM_CIRCBUF
+	depends on EXPERIMENTAL
+	default n
+	---help---
+		IPCC driver. Generic driver to communicate between two
+		processors via character device.
+
+comment "IPCC driver requires CONFIG_EXPERIMENTAL"
+	depends on !EXPERIMENTAL
+
+if IPCC
+
+config IPCC_BUFFERED
+	bool "Enable buffering in driver"
+	default y
+	---help---
+		If enabled, data read and written to/from IPCC will be
+		buffered in driver. This will reduce thread waiting for
+		read and write to complete during busy period, but it
+		will also increase RAM usage.
+
+		Buffer size for tx and rx can be separately defined for
+		each channel during driver registration.
+
+config IPCC_NPOLLWAITERS
+	int "Number of poll threads"
+	default 4
+	---help---
+		Maximum number of threads that can be waiting for POLL events.
+
+endif # IPCC
diff --git a/drivers/ipcc/Make.defs b/drivers/ipcc/Make.defs
new file mode 100644
index 0000000000..0892b0de3d
--- /dev/null
+++ b/drivers/ipcc/Make.defs
@@ -0,0 +1,41 @@
+############################################################################
+# drivers/ipcc/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifeq ($(CONFIG_IPCC),y)
+
+# Include ipcc driver
+
+CSRCS += ipcc_poll.c
+CSRCS += ipcc_read.c
+CSRCS += ipcc_write.c
+CSRCS += ipcc_register.c
+CSRCS += ipcc_open.c
+CSRCS += ipcc_close.c
+
+ifneq ($(CONFIG_DISABLE_PSEUDOFS_OPERATIONS),y)
+CSRCS += ipcc_unlink.c
+endif
+
+# Include pipe build support
+
+DEPPATH += --dep-path ipcc
+VPATH += :ipcc
+
+endif # $(CONFIG_IPCC),y
diff --git a/drivers/ipcc/ipcc_close.c b/drivers/ipcc/ipcc_close.c
new file mode 100644
index 0000000000..616e4c72fb
--- /dev/null
+++ b/drivers/ipcc/ipcc_close.c
@@ -0,0 +1,94 @@
+/****************************************************************************
+ * drivers/ipcc/ipcc_close.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/semaphore.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ipcc_priv.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcc_close
+ *
+ * Description:
+ *   Closes the driver device. If this is last reference and file has been
+ *   unlinked, we will also free resources allocated by ipcc_register()
+ *
+ * Input Parameters:
+ *   filep - pointer to a file structure to close.
+ *
+ * Returned Value:
+ *   OK on successfull close, or negated errno on failure.
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+int ipcc_close(FAR struct file *filep)
+{
+  FAR struct ipcc_driver_s *priv;
+  int ret;
+
+  /* Get our private data structure */
+
+  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
+  priv = filep->f_inode->i_private;
+
+  /* Get exclusive access to the IPCC driver state structure */
+
+  if ((ret = nxsem_wait(&priv->exclsem)) < 0)
+    {
+      return ret;
+    }
+
+  /* Decrement the count of open references on the driver */
+
+  DEBUGASSERT(priv->crefs > 0);
+  priv->crefs--;
+
+  if (priv->crefs <= 0 && priv->unlinked)
+    {
+      /* If count ref is zero and file has been unlinked, it
+       * means nobody uses the driver and seems like nobody
+       * wants to use it anymore, so free up resources.
+       */
+
+      ipcc_cleanup(priv);
+      return OK;
+    }
+
+  nxsem_post(&priv->exclsem);
+  return OK;
+}
diff --git a/drivers/ipcc/ipcc_open.c b/drivers/ipcc/ipcc_open.c
new file mode 100644
index 0000000000..38c1b68bcb
--- /dev/null
+++ b/drivers/ipcc/ipcc_open.c
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * drivers/ipcc/ipcc_open.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ipcc_priv.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcc_open
+ *
+ * Description:
+ *   Opens driver for use by userspace applications.
+ *
+ * Input Parameters:
+ *   filep - pointer to a file structure to open.
+ *
+ * Returned Value:
+ *   OK on successfull open, or negated errno on failure.
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+int ipcc_open(FAR struct file *filep)
+{
+  FAR struct ipcc_driver_s *priv;
+  int ret;
+
+  /* Get our private data structure */
+
+  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
+  priv = filep->f_inode->i_private;
+
+  /* Get exclusive access to the IPCC driver state structure */
+
+  if ((ret = nxsem_wait(&priv->exclsem)) < 0)
+    {
+      return ret;
+    }
+
+  /* Increment the count of open references on the driver */
+
+  priv->crefs++;
+  DEBUGASSERT(priv->crefs > 0);
+
+  nxsem_post(&priv->exclsem);
+  return OK;
+}
diff --git a/drivers/ipcc/ipcc_poll.c b/drivers/ipcc/ipcc_poll.c
new file mode 100644
index 0000000000..775682e1e8
--- /dev/null
+++ b/drivers/ipcc/ipcc_poll.c
@@ -0,0 +1,203 @@
+/****************************************************************************
+ * drivers/ipcc/ipcc_poll.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/semaphore.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ipcc_priv.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcc_poll
+ *
+ * Description:
+ *   Sets up or tears down poll for the driver associated with filep pointer
+ *
+ * Input Parameters:
+ *   filep - file associated with the driver instance
+ *   fds - The structure describing the events to be monitored, OR NULL if
+ *         this is a request to stop monitoring events.
+ *   setup - true: Setup up the poll; false: Teardown the poll
+ *
+ * Returned Value:
+ *   0: Success; Negated errno on failure
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+int ipcc_poll(FAR struct file *filep, FAR struct pollfd *fds,
+                     bool setup)
+{
+  FAR struct ipcc_driver_s *priv;
+  FAR struct pollfd **slot;
+  pollevent_t eventset;
+  int ret;
+  int i;
+
+  /* Get our private data structure */
+
+  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
+  priv = filep->f_inode->i_private;
+
+  /* Get exclusive access to driver */
+
+  if ((ret = nxsem_wait(&priv->exclsem)) < 0)
+    {
+      /* nxsem_wait() will return on signal, we did not start
+       * any transfer yet, so we can safely return with error
+       */
+
+      return ret;
+    }
+
+  /* Are we setting up the poll? Or tearing it down? */
+
+  if (!setup)
+    {
+      /* We are tearing down the poll */
+
+      slot = (FAR struct pollfd **)fds->priv;
+
+      /* remove all memory of the poll setup */
+
+      *slot = NULL;
+      fds->priv = NULL;
+      nxsem_post(&priv->exclsem);
+      return OK;
+    }
+
+  /* This is a request to set up the poll. Find an available slot
+   * for the poll structure reference
+   */
+
+  for (i = 0; i < CONFIG_IPCC_NPOLLWAITERS; i++)
+    {
+      /* Find an available slot */
+
+      if (!priv->fds[i])
+        {
+          /* Bind the poll structure and this slot */
+
+          priv->fds[i] = fds;
+          fds->priv    = &priv->fds[i];
+          break;
+        }
+    }
+
+  if (i >= CONFIG_IPCC_NPOLLWAITERS)
+    {
+      /* No free poll slot found */
+
+      fds->priv = NULL;
+      nxsem_post(&priv->exclsem);
+      return -EBUSY;
+    }
+
+  /* Should immediately notify on any of the requested events?  */
+
+  eventset = 0;
+  if (circbuf_used(&priv->ipcc->rxbuf) > 0)
+    {
+      eventset |= (fds->events & POLLIN);
+    }
+
+  if (circbuf_space(&priv->ipcc->txbuf) > 0)
+    {
+      eventset |= (fds->events & POLLOUT);
+    }
+
+  if (eventset)
+    {
+      ipcc_pollnotify(priv, eventset);
+    }
+
+  nxsem_post(&priv->exclsem);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ipcc_pollnotify
+ *
+ * Description:
+ *   Wakes up all sleeping threads waiting for event associated with ipcc
+ *   driver.
+ *
+ * Input Parameters:
+ *   ipcc - driver instance to check for poll events
+ *   eventset - list of events to check for activity
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions/Limitations:
+ *   This function may be called from interrupt handler.
+ *
+ ****************************************************************************/
+
+void ipcc_pollnotify(FAR struct ipcc_driver_s *priv, pollevent_t eventset)
+{
+  struct pollfd *fds;
+  int semcount;
+  int i;
+
+  for (i = 0; i < CONFIG_IPCC_NPOLLWAITERS; i++)
+    {
+      if ((fds = priv->fds[i]) == NULL)
+        {
+          /* Slot empty, move to next one */
+
+          continue;
+        }
+
+      if ((fds->revents |= fds->events & eventset) == 0)
+        {
+          /* No event */
+
+          continue;
+        }
+
+      finfo("Report events: %08" PRIx32 "\n", fds->revents);
+
+      nxsem_get_value(fds->sem, &semcount);
+      if (semcount < 1)
+        {
+          nxsem_post(fds->sem);
+        }
+    }
+}
diff --git a/drivers/ipcc/ipcc_priv.h b/drivers/ipcc/ipcc_priv.h
new file mode 100644
index 0000000000..398c6446e5
--- /dev/null
+++ b/drivers/ipcc/ipcc_priv.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+ * drivers/ipcc/ipcc_priv.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+#include <stdio.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Driver state structure */
+
+struct ipcc_driver_s
+{
+  FAR struct pollfd        *fds[CONFIG_IPCC_NPOLLWAITERS];
+  FAR struct ipcc_lower_s  *ipcc;     /* Lower half driver state */
+  int                       crefs;    /* Count number of open references */
+  int                       unlinked; /* 1 - driver has been unlinked */
+  sem_t                     exclsem;  /* Mutual exclusion for driver */
+  sem_t                     rxsem;    /* Data ready to read semaphore */
+  sem_t                     txsem;    /* Data ready to send semaphore */
+};
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+int ipcc_open(FAR struct file *filep);
+int ipcc_close(FAR struct file *filep);
+int ipcc_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
+ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer, size_t buflen);
+ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
+                          size_t buflen);
+int ipcc_poll(FAR struct file *filep, FAR struct pollfd *fds,
+                  bool setup);
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+int ipcc_unlink(FAR struct inode *inode);
+#endif
+
+void ipcc_pollnotify(FAR struct ipcc_driver_s *ipcc, pollevent_t eventset);
+void ipcc_cleanup(FAR struct ipcc_driver_s *priv);
diff --git a/drivers/ipcc/ipcc_read.c b/drivers/ipcc/ipcc_read.c
new file mode 100644
index 0000000000..733575f147
--- /dev/null
+++ b/drivers/ipcc/ipcc_read.c
@@ -0,0 +1,232 @@
+/****************************************************************************
+ * drivers/ipcc/ipcc_read.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/semaphore.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ipcc_priv.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcc_rxfree_notify
+ *
+ * Description:
+ *   Notifies all blocked threads or those waiting in poll/select that
+ *   there is data on buffer to perform reading.
+ *
+ * Input Parameters:
+ *   ipcc - pointer to driver instance
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions/Limitations:
+ *   This function can be called from interrupt handler from lower half.
+ *
+ ****************************************************************************/
+
+void ipcc_rxfree_notify(FAR struct ipcc_driver_s *priv)
+{
+  int semval;
+
+  if (priv == NULL)
+    {
+      /* priv can be NULL when ipcc lower half is initialized but
+       * upper half has not yet been initialized, and rx interrupt
+       * has been received. In such case we don't wake any reader,
+       * because since ipcc is not yet initialized there cannot be
+       * any readers yet. We can safely return here, first read()
+       * to this ipcc channel will immediately read data.
+       */
+
+      return;
+    }
+
+  if ((nxsem_get_value(&priv->rxsem, &semval) == 0) && semval > 0)
+    {
+      /* Notify all poll/select waiters that they can read from the driver.
+       * Do it only when there are no already blocked readers to avoid
+       * situation where thread that is polling gets notified only to
+       * be blocked in read() because another thread have read from
+       * buffer before polling thread could.
+       */
+
+      ipcc_pollnotify(priv, POLLIN);
+      return;
+    }
+
+  /* Notify all blocked readers that data is available to read */
+
+  do
+    {
+      nxsem_post(&priv->rxsem);
+    }
+  while (nxsem_get_value(&priv->rxsem, &semval) == 0 && semval <= 0);
+}
+
+/****************************************************************************
+ * Name: ipcc_read
+ *
+ * Description:
+ *   Reads data from the IPCC lower driver. Will block if no data is
+ *   available, unless O_NONBLOCK flag is set.
+ *
+ * Input Parameters:
+ *   filep - file on vfs associated with the driver
+ *   buffer - buffer where read data should be copied to
+ *   buflen - size of the buffer... buffer
+ *
+ * Returned Value:
+ *   Will return number of bytes read or negated errno
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+ssize_t ipcc_read(FAR struct file *filep, FAR char *buffer,
+                         size_t buflen)
+{
+  FAR struct ipcc_driver_s *priv;
+  ssize_t nread;
+  int ret;
+
+  /* Get our private data structure */
+
+  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
+  priv = filep->f_inode->i_private;
+
+  /* Get exclusive access to driver */
+
+  if ((ret = nxsem_wait(&priv->exclsem)))
+    {
+      /* nxsem_wait() will return on signal, we did not start
+       * any transfer yet, so we can safely return with error
+       */
+
+      return ret;
+    }
+
+  for (; ; )
+    {
+#ifdef CONFIG_IPCC_BUFFERED
+      /* Data is buffered in interrupt handler, so we simply
+       * have to return buffers content to the user
+       */
+
+      if ((nread = circbuf_read(&priv->ipcc->rxbuf, buffer, buflen)) > 0)
+        {
+          /* got some data */
+
+          if (priv->ipcc->overflow)
+            {
+              /* We tried to buffer data in previous interrupt, but
+               * it failed due to rxbuf being full. Now that we took
+               * some data from buffer, we can try to buffer data again
+               */
+
+              priv->ipcc->ops.buffer_data(priv->ipcc, &priv->ipcc->rxbuf);
+
+              if ((size_t)nread < buflen)
+                {
+                  /* There is still some space left on buffer, and
+                   * we just added new data to buffer, get more data
+                   * for the user
+                   */
+
+                  nread += circbuf_read(&priv->ipcc->rxbuf, buffer + nread,
+                                        buflen - nread);
+                }
+            }
+
+          /* return number of bytes read to the caller */
+
+          nxsem_post(&priv->exclsem);
+          return nread;
+        }
+
+#else /* CONFIG_IPCC_BUFFERED */
+
+      /* Unbuffered read, read data directly from lower driver */
+
+      if ((nread = priv->ipcc->ops.read(&priv->ipcc, buffer, buflen)) != 0)
+        {
+          /* Got some data, return number of bytes read to the caller
+           *   --or--
+           * read() returned error in which case return errno value
+           */
+
+          nxsem_post(&priv->exclsem);
+          return nread;
+        }
+#endif /* CONFIG_IPCC_BUFFERED */
+
+      /* no data on the buffer, should we block? */
+
+      if (filep->f_oflags & O_NONBLOCK)
+        {
+          /* No, we should not block, so inform caller that
+           * no data could be read
+           */
+
+          nxsem_post(&priv->exclsem);
+          return -EAGAIN;
+        }
+
+      /* We are in blocking mode, so we have to wait for data to arrive */
+
+      nxsem_post(&priv->exclsem);
+      if ((ret = nxsem_wait(&priv->rxsem)))
+        {
+          /* We were interrupted by signal, but we have not written
+           * any data to caller's buffer, so we return with error
+           */
+
+          return ret;
+        }
+
+      /* Data should now be available, but it's possible that
+       * another thread will read all data from buffer before
+       * we can do it, so we will stay in the loop until we
+       * manage to read something - or interrupt signal occurs
+       *
+       * We have released exclusive lock to driver when we were
+       * waiting for data, so now let's retake it.
+       */
+
+      nxsem_wait(&priv->exclsem);
+      continue;
+    }
+}
diff --git a/drivers/ipcc/ipcc_register.c b/drivers/ipcc/ipcc_register.c
new file mode 100644
index 0000000000..22d0736b88
--- /dev/null
+++ b/drivers/ipcc/ipcc_register.c
@@ -0,0 +1,189 @@
+/****************************************************************************
+ * drivers/ipcc/ipcc_register.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mm/circbuf.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ipcc_priv.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Device naming ************************************************************/
+
+#define DEVNAME_FMT     "/dev/ipcc%d"
+#define DEVNAME_FMTLEN  (9 + 3 + 1)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations ipcc_fops =
+{
+#ifdef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  .unlink = NULL,
+#else /* CONFIG_DISABLE_PSEUDOFS_OPERATIONS */
+  .unlink = ipcc_unlink,
+#endif /* CONFIG_DISABLE_PSEUDOFS_OPERATIONS */
+  .open   = ipcc_open,
+  .close  = ipcc_close,
+  .poll   = ipcc_poll,
+  .read   = ipcc_read,
+  .write  = ipcc_write,
+  .ioctl  = NULL,
+  .seek   = NULL
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcc_cleanup
+ *
+ * Description:
+ *   Cleans up resources allocated by ipcc_register()
+ *
+ * Input Parameters:
+ *   priv - ipcc driver instance to clean up
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions/Limitations:
+ *   This function should be called only when ipcc_register is run with
+ *   success and all resources in driver instance are properly allocated.
+ *
+ ****************************************************************************/
+
+void ipcc_cleanup(FAR struct ipcc_driver_s *priv)
+{
+#ifdef CONFIG_IPCC_BUFFERED
+  circbuf_uninit(&priv->ipcc->rxbuf);
+  circbuf_uninit(&priv->ipcc->txbuf);
+#endif
+  nxsem_destroy(&priv->rxsem);
+  nxsem_destroy(&priv->txsem);
+  priv->ipcc->ops.cleanup(priv->ipcc);
+  nxsem_destroy(&priv->exclsem);
+  kmm_free(priv);
+}
+
+/****************************************************************************
+ * Name: ipcc_register
+ *
+ * Description:
+ *   Create and register the IPCC character driver.
+ *
+ *   IPCC is a simple character driver that supports inter processor
+ *   communication.
+ *
+ * Input Parameters:
+ *   ipcc - An instance of the lower half IPCC driver
+ *   chan - IPCC channel. This will be used ad IPCC minor number.
+ *     IPPC will be registered as /dev/ipccN where N is the minor number.
+ *   buflen - Length of tx and rx buffers, 0 for unbuffered communication.
+ *
+ * Returned Value:
+ *   OK if the driver was successfully registered, or negated errno on
+ *   failure.
+ *
+ * Assumptions/Limitations:
+ *   ipcc is already allocated and initialized by architecture code.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IPCC_BUFFERED
+int ipcc_register(FAR struct ipcc_lower_s *ipcc, size_t rxbuflen,
+                  size_t txbuflen)
+#else
+int ipcc_register(FAR struct ipcc_lower_s *ipcc)
+#endif
+{
+  FAR struct ipcc_driver_s *priv;
+  char devname[DEVNAME_FMTLEN];
+  int ret;
+
+  /* Allocate a IPCC character device structure */
+
+  if ((priv = kmm_zalloc(sizeof(*priv))) == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  /* Link upper and lower driver together */
+
+  priv->ipcc = ipcc;
+  ipcc->upper = priv;
+
+#ifdef CONFIG_IPCC_BUFFERED
+  /* allocate buffers for reading and writing data to IPCC memory */
+
+  if (rxbuflen)
+    {
+      if ((ret = circbuf_init(&priv->ipcc->rxbuf, NULL, rxbuflen)))
+        {
+          goto error;
+        }
+    }
+
+  if (txbuflen)
+    {
+      if ((ret = circbuf_init(&priv->ipcc->txbuf, NULL, txbuflen)))
+        {
+          goto error;
+        }
+    }
+#endif /* CONFIG_IPCC_BUFFERED */
+
+  /* Create the character device name */
+
+  snprintf(devname, DEVNAME_FMTLEN, DEVNAME_FMT, ipcc->chan);
+  if ((ret = register_driver(devname, &ipcc_fops, 0666, priv)))
+    {
+      goto error;
+    }
+
+  /* nxsem_init can't really fail us if we provide it with valid params */
+
+  nxsem_init(&priv->exclsem, 0, 1);
+  nxsem_init(&priv->rxsem, 0, 0);
+  nxsem_init(&priv->txsem, 0, 1);
+
+  return OK;
+
+error:
+  ipcc_cleanup(priv);
+
+  return ret;
+}
diff --git a/drivers/ipcc/ipcc_unlink.c b/drivers/ipcc/ipcc_unlink.c
new file mode 100644
index 0000000000..0992631755
--- /dev/null
+++ b/drivers/ipcc/ipcc_unlink.c
@@ -0,0 +1,96 @@
+/****************************************************************************
+ * drivers/ipcc/ipcc_unlink.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/semaphore.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ipcc_priv.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcc_unlink
+ *
+ * Description:
+ *   Action to take upon file unlinking. Function will free resources if
+ *   noone is using the driver when unlinking occured. If driver is still
+ *   in use, it will be marked as unlinked and resource freeing will take
+ *   place in ipcc_close() function instead, once last reference is closed.
+ *
+ * Input Parameters:
+ *   inode - driver inode that is being unlinked
+ *
+ * Returned Value:
+ *   OK on successfull close, or negated errno on failure.
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+int ipcc_unlink(FAR struct inode *inode)
+{
+  FAR struct ipcc_driver_s *priv;
+  int ret;
+
+  /* Get our private data structure */
+
+  DEBUGASSERT(inode);
+  priv = inode->i_private;
+
+  /* Get exclusive access to the IPCC driver state structure */
+
+  if ((ret = nxsem_wait(&priv->exclsem)) < 0)
+    {
+      return ret;
+    }
+
+  /* Is anyone still using the driver? */
+
+  if (priv->crefs <= 0)
+    {
+      /* No, we are free to free resources */
+
+      ipcc_cleanup(priv);
+      return OK;
+    }
+
+  /* Yes, someone is still using the driver, just mark file
+   * as unlinked and free resources in ipcc_close() once last
+   * reference is closed
+   */
+
+  priv->unlinked = true;
+  nxsem_post(&priv->exclsem);
+  return OK;
+}
diff --git a/drivers/ipcc/ipcc_write.c b/drivers/ipcc/ipcc_write.c
new file mode 100644
index 0000000000..bfe420f96d
--- /dev/null
+++ b/drivers/ipcc/ipcc_write.c
@@ -0,0 +1,256 @@
+/****************************************************************************
+ * drivers/ipcc/ipcc_write.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/semaphore.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ipcc_priv.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcc_txfree_notify
+ *
+ * Description:
+ *   Notifies all blocked threads or those waiting in poll/select that
+ *   there is place on buffer to perform writing.
+ *
+ * Input Parameters:
+ *   ipcc - pointer to driver instance
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions/Limitations:
+ *   This function can be called from interrupt handler from lower half.
+ *
+ ****************************************************************************/
+
+void ipcc_txfree_notify(FAR struct ipcc_driver_s *priv)
+{
+  int semval;
+
+  if (priv == NULL)
+    {
+      /* priv can be NULL when ipcc lower half is initialized but
+       * upper half has not yet been initialized, and tx interrupt
+       * has been received. In such case we don't wake any writers,
+       * because since ipcc is not yet initialized there cannot be
+       * any writers yet. We can safely return here, first write()
+       * to this ipcc channel will immediately write data.
+       */
+
+      return;
+    }
+
+  if ((nxsem_get_value(&priv->txsem, &semval) == 0) && semval > 0)
+    {
+      /* Notify all poll/select waiters that they can write to the driver.
+       * Do it only when there are no already blocked writers to avoid
+       * situation where thread that is polling gets notified only to
+       * be blocked in write() because another thread have written to
+       * buffer before polling thread could.
+       */
+
+      ipcc_pollnotify(priv, POLLOUT);
+      return;
+    }
+
+  /* Notify all blocked writers that data is available to write */
+
+  do
+    {
+      nxsem_post(&priv->txsem);
+    }
+  while (nxsem_get_value(&priv->txsem, &semval) == 0 && semval <= 0);
+}
+
+/****************************************************************************
+ * Name: ipcc_write
+ *
+ * Description:
+ *   Writes data to IPCC memory so that another CPU can read the contents.
+ *   Will block untill whole buffer is copied unless signal is received
+ *   or O_NONBLOCK flag is set.
+ *
+ * Input Parameters:
+ *   filep - file on vfs associated with the driver
+ *   buffer - buffer to copy to IPCC memory
+ *   buflen - size of the buffer... buffer
+ *
+ * Returned Value:
+ *   Number of successfully written bytes into the IPCC memory or netagted
+ *   errno when no data could be written.
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+ssize_t ipcc_write(FAR struct file *filep, FAR const char *buffer,
+                         size_t buflen)
+{
+  FAR struct ipcc_driver_s *priv;
+  ssize_t nwritten;
+  int ret;
+
+  /* Get our private data structure */
+
+  DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
+  priv = filep->f_inode->i_private;
+
+  /* Get exclusive access to driver */
+
+  if ((ret = nxsem_wait(&priv->exclsem)))
+    {
+      /* nxsem_wait() will return on signal, we did not start
+       * any transfer yet, so we can safely return with error
+       */
+
+      return ret;
+    }
+
+  for (nwritten = 0; ; )
+    {
+#ifdef CONFIG_IPCC_BUFFERED
+      /* Buffered write, if buffer is empty try to write directly to
+       * IPCC memory, else buffer data in circbuf - it will be written
+       * in interrupt handler when IPCC tx channel is free.
+       */
+
+      if (circbuf_used(&priv->ipcc->txbuf) == 0)
+        {
+          /* Write buffer is empty, we can try and write data directly
+           * to IPCC memory thus omitting copying to buffer.
+           */
+
+          nwritten += priv->ipcc->ops.write(priv->ipcc, buffer + nwritten,
+                                           buflen - nwritten);
+          if (nwritten == (ssize_t)buflen || nwritten < 0)
+            {
+              /* We've managed to write whole buffer to IPCC memory,
+               * there is nothing else for use to do
+               *   --or--
+               * lower half driver returned error during write,
+               *
+               * either way we return with nwritten which will either
+               * be number of bytes written or negated errno.
+               */
+
+              nxsem_post(&priv->exclsem);
+              return nwritten;
+            }
+        }
+
+      /* Either, there is already some data on the txbuffer, which
+       * means IPCC is occupied, or txbuffer is empty, but we could
+       * not write whole buffer to IPCC memory. In either case we
+       * copy what is left in data to buffer.
+       */
+
+      nwritten += circbuf_write(&priv->ipcc->txbuf, buffer + nwritten,
+                                (ssize_t)buflen - nwritten);
+
+      /* Notify lower half that new data on circ buffer is available */
+
+      priv->ipcc->ops.write_notify(priv->ipcc);
+
+      if (nwritten == (ssize_t)buflen)
+        {
+          /* All outstanding data has been copied to txbuffer, we're done */
+
+          nxsem_post(&priv->exclsem);
+          return nwritten;
+        }
+
+#else /* CONFIG_IPCC_BUFFERED */
+      /* Unbuffered write, write data directly to lower driver */
+
+      nwritten += priv->ipcc->ops.write(&priv->ipcc, buffer, buflen);
+      if (nwritten == (ssize_t)buflen)
+        {
+          /* We've managed to write whole buffer to IPCC memory,
+           * there is nothing else for use to do
+           *   --or--
+           * lower half driver returned error during write,
+           *
+           * either way we return with nwritten which will either
+           * be number of bytes written or negated errno.
+           */
+
+          nxsem_post(&priv->exclsem);
+          return nwritten;
+        }
+
+#endif /* CONFIG_IPCC_BUFFERED */
+
+      /* No space left on buffer, should we block? */
+
+      if (filep->f_oflags & O_NONBLOCK)
+        {
+          /* No, we should not block, return number of bytes written or
+           * -EAGAIN when we did not write anything
+           */
+
+          nxsem_post(&priv->exclsem);
+          return nwritten ? nwritten : -EAGAIN;
+        }
+
+      /* We are in blocking mode, so we have to wait for space
+       * to write data
+       */
+
+      nxsem_post(&priv->exclsem);
+      if ((ret = nxsem_wait(&priv->txsem)))
+        {
+          /* We were interrupted by signal, return error or number
+           * of bytes written
+           */
+
+          return nwritten ? nwritten : -EINTR;
+        }
+
+      /* Space should now be available, but it's possible that
+       * another thread will write data to txbuffer before
+       * we can do it, so we will stay in the loop until we
+       * manage to write whole buffer - or interrupt signal occurs.
+       *
+       * We have released exclusive lock to driver when we were
+       * waiting for data, so now let's retake it.
+       */
+
+      nxsem_wait(&priv->exclsem);
+      continue;
+    }
+}
diff --git a/include/nuttx/ipcc.h b/include/nuttx/ipcc.h
new file mode 100644
index 0000000000..863513e3c9
--- /dev/null
+++ b/include/nuttx/ipcc.h
@@ -0,0 +1,204 @@
+/****************************************************************************
+ * include/nuttx/ipcc.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_IPCC_H
+#define __INCLUDE_NUTTX_IPCC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/mm/circbuf.h>
+#include <nuttx/semaphore.h>
+
+#include <poll.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* IPCC is a two-part driver:
+ *
+ * 1) A common upper half driver, that provides the character device
+ *    interface for the user
+ * 2) Platform-specific lower half drivers that provide interface
+ *    between upper and lower layer. Lower half also contains
+ *    common objects like semaphore to inform
+ */
+
+/* This structure defines all of the operations provided by the
+ * architecture specific logic. All fields must be provided with
+ * non-NULL function pointers.
+ */
+
+struct ipcc_lower_s;
+struct ipcc_ops_s
+{
+  /**************************************************************************
+   * Name: read
+   *
+   * Description:
+   *   Reads data directly from IPCC mbox, function shall not block.
+   *   If no data is available, 0 shall be returned. Partial read
+   *   is possible. In that case function can return value less
+   *   than buflen.
+   *
+   * Input Parameters:
+   *   ipcc - ipcc channel to read data from
+   *   buffer - location where data shall be stored
+   *   buflen - size of the buffer
+   *
+   * Returned Value:
+   *   Number of bytes actually written to buffer.
+   *
+   **************************************************************************/
+
+  CODE ssize_t (*read)(FAR struct ipcc_lower_s *ipcc,
+                       FAR char *buffer, size_t buflen);
+
+  /**************************************************************************
+   * Name: write
+   *
+   * Description:
+   *   Writes data directly to IPCC mbox, function shall not block.
+   *   If IPCC memory is full, or busy or otherwise unavailable for
+   *   write, 0 shall be returned. Partial write is possible. In
+   *   that case function can return value less then buflen.
+   *
+   * Input Parameters:
+   *   ipcc - ipcc channel to write data to
+   *   buffer - location to read data from
+   *   buflen - number of bytes to write from buffer
+   *
+   * Returned Value:
+   *   Number of actually written data to IPCC channel.
+   *
+   **************************************************************************/
+
+  CODE ssize_t (*write)(FAR struct ipcc_lower_s *ipcc,
+                        FAR const char *buffer, size_t buflen);
+
+  /**************************************************************************
+   * Name: buffer_data
+   *
+   * Description:
+   *   Lower driver shall copy data from IPCC to cirbuf on demand.
+   *   It does not have to copy all data (in case rxbuf is full), but
+   *   it must keep internal pointer to track uncopied data, and copy
+   *   what is left on the next call to this function.
+   *
+   * Input Parameters:
+   *   ipcc - channel to buffer data
+   *   rxbuf - circural buffer where data should be written to
+   *
+   * Returned Value:
+   *   Number of bytes that were successfully written to rxbuf.
+   *
+   **************************************************************************/
+
+  CODE ssize_t (*buffer_data)(FAR struct ipcc_lower_s *ipcc,
+                              FAR struct circbuf_s *rxbuf);
+
+  /**************************************************************************
+   * Name: write_notify
+   *
+   * Description:
+   *   Upper half driver notifies lower half driver that new data has been
+   *   copied to circ buffer. This can be used by lower half to transfer
+   *   data from buffer to IPCC memory.
+   *
+   * Input Parameters:
+   *   ipcc - ipcc channel that wrote data.
+   *
+   * Returned Value:
+   *   0 on success, or negated errno otherwise
+   *
+   **************************************************************************/
+
+  CODE ssize_t (*write_notify)(FAR struct ipcc_lower_s *ipcc);
+
+  /**************************************************************************
+   * Name: cleanup
+   *
+   * Description:
+   *   Cleans up resources initialized by <arch>_ipcc_init(). If arch code
+   *   malloc()ed any memory, this funciton is responsible of freeing it.
+   *   After this function is called, ipcc driver will not access lower
+   *   half pointer anymore.
+   *
+   * Input Parameters:
+   *   ipcc - ipcc channel to cleanup
+   *
+   * Returned Value:
+   *   Always OK
+   *
+   **************************************************************************/
+
+  CODE int (*cleanup)(FAR struct ipcc_lower_s *ipcc);
+};
+
+/* This structure defines the interface between upper and lower halves.
+ * Such instance is passed to ipcc_register() function after driver
+ * has been initialized, binding the upper and lower halves into one
+ * driver.
+ */
+
+struct ipcc_lower_s
+{
+  /* Pointer to upper half part of the driver. This should be used only
+   * when calling ipcc_* upper half functions from lower half code.
+   * There should be no need to access upper half driver's fields from
+   * lower half context.
+   */
+
+  FAR struct ipcc_driver_s *upper;
+  struct ipcc_ops_s         ops;      /* Arch specific functions */
+  int                       chan;     /* IPCC channel */
+
+#ifdef CONFIG_IPCC_BUFFERED
+  struct circbuf_s          rxbuf;    /* Receive buffer */
+  struct circbuf_s          txbuf;    /* Transmit buffer */
+
+  /* 1 - not all data could fit into buffer, some unread data is still
+   * in IPCC mbox. State of this variable is maintained by lower half,
+   * upper half only reads it to know when to inform lower driver that
+   * buffer got free.
+   */
+
+  int                       overflow;
+#endif /* CONFIG_IPCC_BUFFERED */
+};
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+void ipcc_txfree_notify(FAR struct ipcc_driver_s *priv);
+void ipcc_rxfree_notify(FAR struct ipcc_driver_s *priv);
+
+#ifdef CONFIG_IPCC_BUFFERED
+int ipcc_register(FAR struct ipcc_lower_s *ipcc, size_t rxbuflen,
+                  size_t txbuflen);
+#else
+int ipcc_register(FAR struct ipcc_lower_s *ipcc);
+#endif
+
+#endif /* __INCLUDE_NUTTX_IPCC_H */