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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 + +#include +#include + +/**************************************************************************** + * 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 + +#include +#include +#include + +#include +#include + +#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 + +#include + +/**************************************************************************** + * 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 */