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
The following commit(s) were added to refs/heads/master by this push:
new a6c1ef3c52 wireless/bluetooth: add RPMSG HCI controller support
a6c1ef3c52 is described below
commit a6c1ef3c5236ea8f0071ae92b74ee4d76baa7c25
Author: raiden00pl <[email protected]>
AuthorDate: Sat Mar 11 11:06:51 2023 +0100
wireless/bluetooth: add RPMSG HCI controller support
---
drivers/wireless/bluetooth/Kconfig | 10 +
drivers/wireless/bluetooth/Make.defs | 8 +
drivers/wireless/bluetooth/bt_rpmsghci.c | 528 +++++++++++++++++++++++
drivers/wireless/bluetooth/bt_rpmsghci.h | 96 +++++
drivers/wireless/bluetooth/bt_rpmsghci_server.c | 540 ++++++++++++++++++++++++
include/nuttx/wireless/bluetooth/bt_rpmsghci.h | 88 ++++
6 files changed, 1270 insertions(+)
diff --git a/drivers/wireless/bluetooth/Kconfig
b/drivers/wireless/bluetooth/Kconfig
index 41cd7d37d0..356830f96b 100644
--- a/drivers/wireless/bluetooth/Kconfig
+++ b/drivers/wireless/bluetooth/Kconfig
@@ -75,4 +75,14 @@ config BLUETOOTH_NULL
loop" and nothing more: It is a just a bit-bucket for outgoing
packets; it generates no incoming packets.
+config BLUETOOTH_RPMSG_SERVER
+ bool "RPMSG Bluetooth HCI server support"
+ depends on EXPERIMENTAL
+ default n
+
+config BLUETOOTH_RPMSG
+ bool "RPMSG Bluetooth HCI client support"
+ depends on EXPERIMENTAL
+ default n
+
endif # DRIVERS_BLUETOOTH
diff --git a/drivers/wireless/bluetooth/Make.defs
b/drivers/wireless/bluetooth/Make.defs
index 0b7ab95ab7..963a172347 100644
--- a/drivers/wireless/bluetooth/Make.defs
+++ b/drivers/wireless/bluetooth/Make.defs
@@ -48,6 +48,14 @@ ifeq ($(CONFIG_BLUETOOTH_NULL),y)
CSRCS += bt_null.c
endif
+ifeq ($(CONFIG_BLUETOOTH_RPMSG_SERVER),y)
+CSRCS += bt_rpmsghci_server.c
+endif
+
+ifeq ($(CONFIG_BLUETOOTH_RPMSG),y)
+CSRCS += bt_rpmsghci.c
+endif
+
# Include common Bluetooth driver build support
DEPPATH += --dep-path wireless$(DELIM)bluetooth
diff --git a/drivers/wireless/bluetooth/bt_rpmsghci.c
b/drivers/wireless/bluetooth/bt_rpmsghci.c
new file mode 100644
index 0000000000..29cf7288f6
--- /dev/null
+++ b/drivers/wireless/bluetooth/bt_rpmsghci.c
@@ -0,0 +1,528 @@
+/****************************************************************************
+ * drivers/wireless/bluetooth/bt_rpmsghci.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 <sys/param.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/net/bluetooth.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/rptun/openamp.h>
+#include <nuttx/wireless/bluetooth/bt_rpmsghci.h>
+
+#include "bt_rpmsghci.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct rpmsghci_s
+{
+ /* This must be te first thung in the structure so we can simply cast from
+ * struct rpmsghci_s to struct bt_driver_s.
+ */
+
+ struct bt_driver_s btdev;
+ struct rpmsg_endpoint ept;
+ FAR const char *cpuname;
+ FAR const char *name;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int rpmsghci_default_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv);
+static int rpmsghci_recv_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const rpmsg_ept_cb g_rpmsghci_handler[] =
+{
+ rpmsghci_default_handler, /* RPMSGHCI_OPEN */
+ rpmsghci_default_handler, /* RPMSGHCI_CLOSE */
+ rpmsghci_default_handler, /* RPMSGHCI_SEND */
+ rpmsghci_default_handler, /* RPMSGHCI_IOCTL */
+ rpmsghci_recv_handler, /* RPMSGHCI_RECV */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsghci_get_tx_payload_buffer
+ ****************************************************************************/
+
+static FAR void *
+rpmsghci_get_tx_payload_buffer(FAR struct rpmsghci_s *priv,
+ FAR uint32_t *len)
+{
+ return rpmsg_get_tx_payload_buffer(&priv->ept, len, true);
+}
+
+/****************************************************************************
+ * Name: rpmsghci_send
+ *
+ * Description:
+ * Send the rpmsg data and wait for ACK.
+ *
+ * Parameters:
+ * priv - rpmsg device handle
+ * command - the command, RPMSGHCI_OPEN, RPMSGHCI_CLOSE, RPMSGHCI_SEND,
+ * RPMSGHCI_IOCTL
+ * msg - the message header
+ * len - length of the payload
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_send(FAR struct rpmsghci_s *priv, uint32_t command,
+ FAR struct rpmsghci_header_s *msg, int len)
+{
+ struct rpmsghci_cookie_s cookie;
+ int ret = OK;
+
+ memset(&cookie, 0, sizeof(struct rpmsghci_cookie_s));
+ nxsem_init(&cookie.sem, 0, 0);
+
+ msg->command = command;
+ msg->result = -ENXIO;
+ msg->cookie = (uintptr_t)&cookie;
+
+ ret = rpmsg_send_nocopy(&priv->ept, msg, len);
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ ret = rpmsg_wait(&priv->ept, &cookie.sem);
+ if (ret >= 0)
+ {
+ ret = msg->result;
+ }
+
+errout:
+ nxsem_destroy(&cookie.sem);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsghci_bt_open
+ *
+ * Description:
+ * Rpmsg-HCI open operation
+ *
+ * Parameters:
+ * btdev - the bt instance
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_bt_open(struct bt_driver_s *btdev)
+{
+ FAR struct rpmsghci_s *priv = NULL;
+ FAR struct rpmsghci_open_s *msg = NULL;
+ uint32_t space = 0;
+ int ret = OK;
+
+ /* Get RPMSG-HCI data */
+
+ DEBUGASSERT(btdev != NULL);
+ priv = (FAR struct rpmsghci_s *)btdev;
+
+ /* Perform the rpmsg write */
+
+ msg = rpmsghci_get_tx_payload_buffer(priv, &space);
+ if (msg == NULL)
+ {
+ return -ENOMEM;
+ }
+
+ return rpmsghci_send(priv, RPMSGHCI_OPEN, &msg->header,
+ sizeof(struct rpmsghci_open_s));
+}
+
+/****************************************************************************
+ * Name: rpmsghci_bt_close
+ *
+ * Description:
+ * Rpmsg-HCI close operation
+ *
+ * Parameters:
+ * btdev - the bt instance
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static void rpmsghci_bt_close(struct bt_driver_s *btdev)
+{
+ FAR struct rpmsghci_s *priv = NULL;
+ FAR struct rpmsghci_close_s *msg = NULL;
+ uint32_t space = 0;
+
+ /* Get RPMSG-HCI data */
+
+ DEBUGASSERT(btdev != NULL);
+ priv = (FAR struct rpmsghci_s *)btdev;
+
+ /* Perform the rpmsg write */
+
+ msg = rpmsghci_get_tx_payload_buffer(priv, &space);
+ if (msg == NULL)
+ {
+ return;
+ }
+
+ rpmsghci_send(priv, RPMSGHCI_CLOSE, &msg->header,
+ sizeof(struct rpmsghci_close_s));
+}
+
+/****************************************************************************
+ * Name: rpmsghci_bt_send
+ *
+ * Description:
+ * Rpmsg-HCI send operation
+ *
+ * Parameters:
+ * btdev - the bt instance
+ * type - bt command type
+ * data - bt command data
+ * len - bt command data length
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_bt_send(struct bt_driver_s *btdev, uint8_t type,
+ void *data, size_t len)
+{
+ FAR struct rpmsghci_s *priv = NULL;
+ FAR struct rpmsghci_data_s *msg = NULL;
+ uint32_t space = 0;
+ int ret = OK;
+
+ wlinfo("rpmsghci_bt_send %d\n", type);
+
+ /* Get RPMSG-HCI data */
+
+ DEBUGASSERT(btdev != NULL);
+ priv = (FAR struct rpmsghci_s *)btdev;
+
+ if (data == NULL)
+ {
+ return -EINVAL;
+ }
+
+ /* Perform the rpmsg write */
+
+ msg = rpmsghci_get_tx_payload_buffer(priv, &space);
+ if (msg == NULL)
+ {
+ return -ENOMEM;
+ }
+
+ DEBUGASSERT(sizeof(struct rpmsghci_data_s) - 1 + len <= space);
+ memcpy(msg->data, data, len);
+ msg->type = type;
+ return rpmsghci_send(priv, RPMSGHCI_SEND, &msg->header,
+ sizeof(struct rpmsghci_data_s) -1 + len);
+}
+
+/****************************************************************************
+ * Name: rpmsghci_bt_ioctl
+ *
+ * Description:
+ * Rpmsg-HCI ioctl operation
+ *
+ * Parameters:
+ * btdev - the bt instance
+ * cmd - the ioctl command
+ * arg - the ioctl arguments
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_bt_ioctl(FAR struct bt_driver_s *btdev, int cmd,
+ unsigned long arg)
+{
+ /* TODO */
+
+ return -ENOTTY;
+}
+
+/****************************************************************************
+ * Name: rpmsghci_default_handler
+ *
+ * Description:
+ * Default rpmsg-HCI response handler, this function will be called to
+ * process the return message of rpmsghci_open(), rpmsghci_close(),
+ * rpmsghci_send(), rpmsghci_ioctl().
+ *
+ * Parameters:
+ * ept - The rpmsg endpoint
+ * data - The return message
+ * len - The return message length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * Always OK
+ *
+ ****************************************************************************/
+
+static int rpmsghci_default_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_header_s *header = data;
+ FAR struct rpmsghci_cookie_s *cookie = NULL;
+
+ if (header->cookie != 0)
+ {
+ cookie = (FAR struct rpmsghci_cookie_s *)(uintptr_t)header->cookie;
+ return rpmsg_post(ept, &cookie->sem);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsghci_recv_handler
+ *
+ * Description:
+ * Rpmsg-HCI receive handler.
+ *
+ * Parameters:
+ * ept - The rpmsg endpoint
+ * data - The return message
+ * len - The return message length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_recv_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_s *client = NULL;
+ FAR struct rpmsghci_data_s *msg = data;
+ int ret = OK;
+
+ DEBUGASSERT(priv);
+ client = priv;
+
+ wlinfo("rpmsghci_recv_handler %d\n", msg->type);
+
+ ret = bt_netdev_receive(&client->btdev, msg->type, msg->data,
+ len - sizeof(struct rpmsghci_data_s) + 1);
+ msg->header.result = ret;
+
+ return rpmsg_send(ept, msg, sizeof(struct rpmsghci_header_s));
+}
+
+/****************************************************************************
+ * Name: rpmsghci_client_ept_cb
+ *
+ * Description:
+ * Rpmsg HCI end point callback function, this function will be called
+ * when receive the remote cpu message.
+ *
+ * Parameters:
+ * ept - The rpmsg-HCI end point
+ * data - The received data
+ * len - The received data length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_client_ept_cb(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_header_s *header = data;
+ uint32_t command = header->command;
+
+ if (command < nitems(g_rpmsghci_handler))
+ {
+ return g_rpmsghci_handler[command](ept, data, len, src, priv);
+ }
+
+ return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: rpmsghci_client_created
+ *
+ * Description:
+ * Rpmsg HCI create function, this function will be called by rptun to
+ * create a rpmsg-hci end point.
+ *
+ * Parameters:
+ * rdev - The rpmsg-hci end point
+ * priv_ - Rpmsg-hci handle
+ *
+ * Returned Values:
+ * None
+ *
+ ****************************************************************************/
+
+static void rpmsghci_client_created(FAR struct rpmsg_device *rdev,
+ FAR void *priv_)
+{
+ FAR struct rpmsghci_s *priv = priv_;
+ char eptname[RPMSG_NAME_SIZE];
+
+ if (strcmp(priv->cpuname, rpmsg_get_cpuname(rdev)) == 0)
+ {
+ snprintf(eptname, RPMSG_NAME_SIZE, "%s%s", RPMSGHCI_NAME_PREFIX,
+ priv->name);
+ priv->ept.priv = priv;
+ rpmsg_create_ept(&priv->ept, rdev, eptname,
+ RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
+ rpmsghci_client_ept_cb, NULL);
+ }
+}
+
+/****************************************************************************
+ * Name: rpmsghci_client_destroy
+ *
+ * Description:
+ * Rpmsg HCI destroy function, this function will be called by rptun to
+ * destroy rpmsg-HCI end point.
+ *
+ * Parameters:
+ * rdev - The rpmsg-HCI end point
+ * priv_ - Rpmsg-HCI handle
+ *
+ * Returned Values:
+ * None
+ *
+ ****************************************************************************/
+
+static void rpmsghci_client_destroy(FAR struct rpmsg_device *rdev,
+ FAR void *priv_)
+{
+ FAR struct rpmsghci_s *priv = priv_;
+
+ if (!strcmp(priv->cpuname, rpmsg_get_cpuname(rdev)))
+ {
+ rpmsg_destroy_ept(&priv->ept);
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsghci_register
+ *
+ * Description:
+ * Rpmsg-HCI client initialize function, the client cpu should call
+ * this function in the board initialize process.
+ *
+ * Parameters:
+ * cpuname - the server cpu name
+ * name - the HCI device you want to access in the remote cpu
+ *
+ * Returned Values:
+ * A non-NULL handle is returned on success;
+ * A NULL is returned on any failure.
+ *
+ ****************************************************************************/
+
+FAR struct bt_driver_s *rpmsghci_register(FAR const char *cpuname,
+ FAR const char *name)
+{
+ FAR struct rpmsghci_s *priv = NULL;
+
+ /* Validate input */
+
+ if (!cpuname || !name)
+ {
+ return NULL;
+ }
+
+ /* Create RPMSG-HCI driver */
+
+ priv = kmm_zalloc(sizeof(struct rpmsghci_s));
+ if (!priv)
+ {
+ return NULL;
+ }
+
+ /* Initialize BT driver */
+
+ priv->btdev.open = rpmsghci_bt_open;
+ priv->btdev.close = rpmsghci_bt_close;
+ priv->btdev.send = rpmsghci_bt_send;
+ priv->btdev.ioctl = rpmsghci_bt_ioctl;
+
+ /* Initialize RPMSG-HCI client data */
+
+ priv->cpuname = cpuname;
+ priv->name = name;
+
+ /* Register the device with the openamp */
+
+ rpmsg_register_callback(priv,
+ rpmsghci_client_created,
+ rpmsghci_client_destroy,
+ NULL,
+ NULL);
+
+ return &priv->btdev;
+}
diff --git a/drivers/wireless/bluetooth/bt_rpmsghci.h
b/drivers/wireless/bluetooth/bt_rpmsghci.h
new file mode 100644
index 0000000000..f34b0bd6af
--- /dev/null
+++ b/drivers/wireless/bluetooth/bt_rpmsghci.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+ * drivers/wireless/bluetooth/bt_rpmsghci.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 __DRIVERS_WIRELESS_BLUETOOTH_BT_RPMSGHCI_H
+#define __DRIVERS_WIRELESS_BLUETOOTH_BT_RPMSGHCI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+#include <nuttx/compiler.h>
+#include <nuttx/semaphore.h>
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+#define RPMSGHCI_NAME_PREFIX "rpmsghci-"
+#define RPMSGHCI_NAME_PREFIX_LEN 9
+
+#define RPMSGHCI_OPEN 0 /* Device open */
+#define RPMSGHCI_CLOSE 1 /* Device close */
+#define RPMSGHCI_SEND 2 /* Data to a HCI controller */
+#define RPMSGHCI_IOCTL 3 /* Device ioctl */
+#define RPMSGHCI_RECV 4 /* Data from a HCI controller */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Rpmsg device cookie used to handle the response from the remote cpu */
+
+struct rpmsghci_cookie_s
+{
+ sem_t sem;
+};
+
+begin_packed_struct struct rpmsghci_header_s
+{
+ uint32_t command;
+ int32_t result;
+ uint64_t cookie;
+} end_packed_struct;
+
+begin_packed_struct struct rpmsghci_open_s
+{
+ struct rpmsghci_header_s header;
+} end_packed_struct;
+
+#define rpmsghci_close_s rpmsghci_open_s
+
+begin_packed_struct struct rpmsghci_data_s
+{
+ struct rpmsghci_header_s header;
+ uint8_t type;
+ char data[1];
+} end_packed_struct;
+
+begin_packed_struct struct rpmsghci_ioctl_s
+{
+ struct rpmsghci_header_s header;
+ uint64_t filep;
+ uint64_t arg;
+ uint32_t arglen;
+ int32_t request;
+ char buf[1];
+} end_packed_struct;
+
+/****************************************************************************
+ * Internal function prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Internal data
+ ****************************************************************************/
+
+#endif /* __DRIVERS_WIRELESS_BLUETOOTH_BT_RPMSGHCI_H */
diff --git a/drivers/wireless/bluetooth/bt_rpmsghci_server.c
b/drivers/wireless/bluetooth/bt_rpmsghci_server.c
new file mode 100644
index 0000000000..b91cf59770
--- /dev/null
+++ b/drivers/wireless/bluetooth/bt_rpmsghci_server.c
@@ -0,0 +1,540 @@
+/****************************************************************************
+ * drivers/wireless/bluetooth/bt_rpmsghci_server.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 <sys/param.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <stdlib.h>
+
+#include <nuttx/rptun/openamp.h>
+#include <nuttx/wireless/bluetooth/bt_rpmsghci.h>
+
+#include "bt_rpmsghci.h"
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct rpmsghci_server_s
+{
+ struct rpmsg_endpoint ept;
+ FAR struct bt_driver_s *btdev;
+ FAR const char *name;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int rpmsghci_open_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv);
+static int rpmsghci_close_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv);
+static int rpmsghci_send_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv);
+static int rpmsghci_ioctl_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv);
+static int rpmsghci_default_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const rpmsg_ept_cb g_rpmsghci_handler[] =
+{
+ rpmsghci_open_handler, /* RPMSGHCI_OPEN */
+ rpmsghci_close_handler, /* RPMSGHCI_CLOSE */
+ rpmsghci_send_handler, /* RPMSGHCI_SEND */
+ rpmsghci_ioctl_handler, /* RPMSGHCI_IOCTL */
+ rpmsghci_default_handler, /* RPMSGHCI_RECV */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsghci_get_tx_payload_buffer
+ ****************************************************************************/
+
+static FAR void *
+rpmsghci_get_tx_payload_buffer(FAR struct rpmsghci_server_s *priv,
+ FAR uint32_t *len)
+{
+ return rpmsg_get_tx_payload_buffer(&priv->ept, len, true);
+}
+
+/****************************************************************************
+ * Name: rpmsghci_send
+ *
+ * Description:
+ * Send the rpmsg data and wait for ACK.
+ *
+ * Parameters:
+ * priv - rpmsg device handle
+ * command - the command, RPMSGHCI_OPEN, RPMSGHCI_CLOSE, RPMSGHCI_SEND,
+ * RPMSGHCI_IOCTL
+ * msg - the message header
+ * len - length of the payload
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_send(FAR struct rpmsghci_server_s *priv,
+ uint32_t command, FAR struct rpmsghci_header_s *msg,
+ int len)
+{
+ struct rpmsghci_cookie_s cookie;
+ int ret = OK;
+
+ memset(&cookie, 0, sizeof(struct rpmsghci_cookie_s));
+ nxsem_init(&cookie.sem, 0, 0);
+
+ msg->command = command;
+ msg->result = -ENXIO;
+ msg->cookie = (uintptr_t)&cookie;
+
+ ret = rpmsg_send_nocopy(&priv->ept, msg, len);
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ ret = rpmsg_wait(&priv->ept, &cookie.sem);
+ if (ret >= 0)
+ {
+ ret = msg->result;
+ }
+
+errout:
+ nxsem_destroy(&cookie.sem);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsghci_open_handler
+ *
+ * Description:
+ * Rpmsg-HCI device open handler.
+ *
+ * Parameters:
+ * ept - The rpmsg endpoint
+ * data - The return message
+ * len - The return message length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_open_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_server_s *server = NULL;
+ FAR struct bt_driver_s *btdev = NULL;
+ FAR struct rpmsghci_data_s *msg = data;
+ int ret = OK;
+
+ DEBUGASSERT(priv);
+ server = priv;
+ DEBUGASSERT(server->btdev);
+ btdev = server->btdev;
+
+ if (btdev->open)
+ {
+ ret = btdev->open(btdev);
+ }
+
+ msg->header.result = ret;
+
+ return rpmsg_send(ept, msg, sizeof(struct rpmsghci_header_s));
+}
+
+/****************************************************************************
+ * Name: rpmsghci_close_handler
+ *
+ * Description:
+ * Rpmsg-HCI close handler.
+ *
+ * Parameters:
+ * ept - The rpmsg endpoint
+ * data - The return message
+ * len - The return message length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_close_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_server_s *server = NULL;
+ FAR struct bt_driver_s *btdev = NULL;
+ FAR struct rpmsghci_data_s *msg = data;
+ int ret = OK;
+
+ DEBUGASSERT(priv);
+ server = priv;
+ DEBUGASSERT(server->btdev);
+ btdev = server->btdev;
+
+ if (btdev->close)
+ {
+ btdev->close(btdev);
+ }
+
+ msg->header.result = ret;
+
+ return rpmsg_send(ept, msg, sizeof(struct rpmsghci_header_s));
+}
+
+/****************************************************************************
+ * Name: rpmsghci_send_handler
+ *
+ * Description:
+ * Rpmsg-HCI send handler.
+ *
+ * Parameters:
+ * ept - The rpmsg endpoint
+ * data - The return message
+ * len - The return message length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_send_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_server_s *server = NULL;
+ FAR struct bt_driver_s *btdev = NULL;
+ FAR struct rpmsghci_data_s *msg = data;
+ int ret = OK;
+
+ DEBUGASSERT(priv);
+ server = priv;
+ DEBUGASSERT(server->btdev);
+ btdev = server->btdev;
+
+ wlinfo("rpmsghci_send_handler %d\n", msg->type);
+
+ ret = btdev->send(btdev, msg->type, msg->data,
+ len - sizeof(struct rpmsghci_data_s) + 1);
+
+ msg->header.result = ret;
+
+ return rpmsg_send(ept, msg, sizeof(struct rpmsghci_header_s));
+}
+
+/****************************************************************************
+ * Name: rpmsghci_ioctl_handler
+ *
+ * Description:
+ * Rpmsg-HCI ioctl handler.
+ *
+ * Parameters:
+ * ept - The rpmsg endpoint
+ * data - The return message
+ * len - The return message length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_ioctl_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_server_s *server = NULL;
+ FAR struct bt_driver_s *btdev = NULL;
+ FAR struct rpmsghci_ioctl_s *msg = data;
+ int ret = OK;
+
+ DEBUGASSERT(priv);
+ server = priv;
+ DEBUGASSERT(server->btdev);
+ btdev = server->btdev;
+
+ ret = btdev->ioctl(btdev, msg->request,
+ msg->arglen > 0 ? (unsigned long)msg->buf :
+ msg->arg);
+
+ msg->header.result = ret;
+
+ /* Send the entire frame so as not to lose ioctl returned data */
+
+ return rpmsg_send(ept, msg, len);
+}
+
+/****************************************************************************
+ * Name: rpmsghci_default_handler
+ *
+ * Description:
+ * Default rpmsg-HCI response handler, this function will be called to
+ * process the return message of rpmsghci_recv()
+ *
+ * Parameters:
+ * ept - The rpmsg endpoint
+ * data - The return message
+ * len - The return message length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * Always OK
+ *
+ ****************************************************************************/
+
+static int rpmsghci_default_handler(FAR struct rpmsg_endpoint *ept,
+ FAR void *data, size_t len,
+ uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_header_s *header = data;
+ FAR struct rpmsghci_cookie_s *cookie = NULL;
+
+ if (header->cookie != 0)
+ {
+ cookie = (FAR struct rpmsghci_cookie_s *)(uintptr_t)header->cookie;
+ return rpmsg_post(ept, &cookie->sem);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsghci_ns_match
+ *
+ * Description:
+ * Check if we match to the rpmsg name service.
+ *
+ ****************************************************************************/
+
+static bool rpmsghci_ns_match(FAR struct rpmsg_device *rdev, FAR void *priv,
+ FAR const char *name, uint32_t dest)
+{
+ return !strncmp(name, RPMSGHCI_NAME_PREFIX, RPMSGHCI_NAME_PREFIX_LEN);
+}
+
+/****************************************************************************
+ * Name: rpmsghci_ept_cb
+ *
+ * Description:
+ * Rpmsg HCI end point callback function, this function will be called
+ * when receive the client cpu message.
+ *
+ * Parameters:
+ * ept - The rpmsg-HCI end point
+ * data - The received data
+ * len - The received data length
+ * src - unknow
+ * priv - unknow
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsghci_ept_cb(FAR struct rpmsg_endpoint *ept, FAR void *data,
+ size_t len, uint32_t src, FAR void *priv)
+{
+ FAR struct rpmsghci_header_s *header = data;
+ uint32_t command = header->command;
+
+ if (command < nitems(g_rpmsghci_handler))
+ {
+ return g_rpmsghci_handler[command](ept, data, len, src, priv);
+ }
+
+ return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: rpmsghci_ns_unbind
+ *
+ * Description:
+ * Unbind from the rpmsg name service.
+ *
+ ****************************************************************************/
+
+static void rpmsghci_ns_unbind(FAR struct rpmsg_endpoint *ept)
+{
+ rpmsg_destroy_ept(ept);
+ kmm_free(ept);
+}
+
+/****************************************************************************
+ * Name: rpmsghci_ns_bind
+ *
+ * Description:
+ * Bind to the rpmsg name service.
+ *
+ ****************************************************************************/
+
+static void rpmsghci_ns_bind(FAR struct rpmsg_device *rdev, FAR void *priv,
+ FAR const char *name, uint32_t dest)
+{
+ FAR struct rpmsghci_server_s *server = priv;
+
+ server->ept.priv = priv;
+ rpmsg_create_ept(&server->ept, rdev, name,
+ RPMSG_ADDR_ANY, dest,
+ rpmsghci_ept_cb, rpmsghci_ns_unbind);
+}
+
+/****************************************************************************
+ * Name: rpmsghci_bt_receive
+ *
+ * Description:
+ * Called by the Bluetooth low-level driver when new data is received from
+ * the radio. Transfers data to the RPMSG client.
+ *
+ * This callback should not be called from the interrupt context !
+ *
+ * Returned Value:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int rpmsghci_bt_receive(FAR struct bt_driver_s *btdev, uint8_t type,
+ FAR void *data, size_t len)
+{
+ FAR struct rpmsghci_server_s *priv = NULL;
+ FAR struct rpmsghci_data_s *msg = NULL;
+ uint32_t space = 0;
+ int ret = OK;
+
+ wlinfo("rpmsghci_bt_receive %d\n", type);
+
+ /* Get RPMSG-HCI data */
+
+ DEBUGASSERT(btdev != NULL);
+ priv = btdev->priv;
+
+ if (data == NULL)
+ {
+ return -EINVAL;
+ }
+
+ /* Perform the rpmsg write */
+
+ msg = rpmsghci_get_tx_payload_buffer(priv, &space);
+ if (msg == NULL)
+ {
+ return -ENOMEM;
+ }
+
+ DEBUGASSERT(sizeof(struct rpmsghci_data_s) - 1 + len <= space);
+ memcpy(msg->data, data, len);
+ msg->type = type;
+ return rpmsghci_send(priv, RPMSGHCI_RECV, &msg->header,
+ sizeof(struct rpmsghci_data_s) -1 + len);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsghci_server_init
+ *
+ * Description:
+ * Rpmsg-HCI server initialize function, the server cpu should call
+ * this function.
+ *
+ * Parameters:
+ * name - RPMSG-HCI server name
+ * bt - BT device handler
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int rpmshci_server_init(FAR const char *name, FAR struct bt_driver_s *btdev)
+{
+ struct rpmsghci_server_s *priv = NULL;
+ int ret = OK;
+
+ /* Validate input */
+
+ if (!name || !btdev)
+ {
+ return -EINVAL;
+ }
+
+ /* Create RPMSG-HCI server */
+
+ priv = kmm_zalloc(sizeof(struct rpmsghci_server_s));
+ if (!priv)
+ {
+ return -ENOMEM;
+ }
+
+ /* Connect BT receive callback and RPMSG as priv */
+
+ btdev->receive = rpmsghci_bt_receive;
+ btdev->priv = priv;
+
+ /* Initialize RPMSG-HCI server data */
+
+ priv->name = name;
+ priv->btdev = btdev;
+
+ ret = rpmsg_register_callback(priv, NULL, NULL,
+ rpmsghci_ns_match,
+ rpmsghci_ns_bind);
+ if (ret < 0)
+ {
+ kmm_free(priv);
+ }
+
+ return ret;
+}
diff --git a/include/nuttx/wireless/bluetooth/bt_rpmsghci.h
b/include/nuttx/wireless/bluetooth/bt_rpmsghci.h
new file mode 100644
index 0000000000..fb0381179a
--- /dev/null
+++ b/include/nuttx/wireless/bluetooth/bt_rpmsghci.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * include/nuttx/wireless/bluetooth/bt_rpmsghci.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_WIRELESS_BLUETOOTH_BT_RPMSGHCI_H
+#define __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_RPMSGHCI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/wireless/bluetooth/bt_driver.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_BLUETOOTH_RPMSG_SERVER
+
+/****************************************************************************
+ * Name: rpmsghci_server_init
+ *
+ * Description:
+ * Rpmsg-HCI server initialize function, the server cpu should call
+ * this function.
+ *
+ * Parameters:
+ * name - RPMSG-HCI server name
+ * bt - BT device handler
+ *
+ * Returned Values:
+ * OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int rpmshci_server_init(FAR const char *name, FAR struct bt_driver_s *dev);
+#endif
+
+#ifdef CONFIG_BLUETOOTH_RPMSG
+
+/****************************************************************************
+ * Name: rpmsghci_register
+ *
+ * Description:
+ * Rpmsg-HCI client initialize function, the client cpu should call
+ * this function in the board initialize process.
+ *
+ * Parameters:
+ * cpuname - the server cpu name
+ * name - the HCI device you want to access in the remote cpu
+ *
+ * Returned Values:
+ * A non-NULL handle is returned on success;
+ * A NULL is returned on any failure.
+ *
+ ****************************************************************************/
+
+FAR struct bt_driver_s *rpmsghci_register(FAR const char *remotecpu,
+ FAR const char *name);
+#endif
+
+#endif /* __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_RPMSGHCI_H */