From f56710c121b87019dc92127993b63b22c27d1d07 Mon Sep 17 00:00:00 2001 From: wangbowen6 Date: Wed, 26 Oct 2022 13:14:49 +0800 Subject: [PATCH] rpmsgblk: rpmsg block device support Like rpmsgdev and rpmsgmtd, rpmsgblk allow the local cpu to access the block device in the remote cpu. Signed-off-by: wangbowen6 --- boards/sim/sim/sim/configs/rpproxy/defconfig | 1 + boards/sim/sim/sim/configs/rpserver/defconfig | 1 + boards/sim/sim/sim/src/sim_bringup.c | 19 + drivers/drivers_initialize.c | 5 + drivers/misc/Kconfig | 10 + drivers/misc/Make.defs | 8 + drivers/misc/rpmsgblk.c | 1106 +++++++++++++++++ drivers/misc/rpmsgblk.h | 109 ++ drivers/misc/rpmsgblk_server.c | 402 ++++++ include/nuttx/drivers/rpmsgblk.h | 90 ++ 10 files changed, 1751 insertions(+) create mode 100644 drivers/misc/rpmsgblk.c create mode 100644 drivers/misc/rpmsgblk.h create mode 100644 drivers/misc/rpmsgblk_server.c create mode 100644 include/nuttx/drivers/rpmsgblk.h diff --git a/boards/sim/sim/sim/configs/rpproxy/defconfig b/boards/sim/sim/sim/configs/rpproxy/defconfig index 7778d624e1..c28136a04b 100644 --- a/boards/sim/sim/sim/configs/rpproxy/defconfig +++ b/boards/sim/sim/sim/configs/rpproxy/defconfig @@ -11,6 +11,7 @@ CONFIG_ARCH_BOARD="sim" CONFIG_ARCH_BOARD_SIM=y CONFIG_ARCH_CHIP="sim" CONFIG_ARCH_SIM=y +CONFIG_BLK_RPMSG=y CONFIG_BOARDCTL_POWEROFF=y CONFIG_BUILTIN=y CONFIG_DEBUG_ASSERTIONS=y diff --git a/boards/sim/sim/sim/configs/rpserver/defconfig b/boards/sim/sim/sim/configs/rpserver/defconfig index 03170c742b..b94cba812b 100644 --- a/boards/sim/sim/sim/configs/rpserver/defconfig +++ b/boards/sim/sim/sim/configs/rpserver/defconfig @@ -10,6 +10,7 @@ CONFIG_ARCH_BOARD="sim" CONFIG_ARCH_BOARD_SIM=y CONFIG_ARCH_CHIP="sim" CONFIG_ARCH_SIM=y +CONFIG_BLK_RPMSG_SERVER=y CONFIG_BOARDCTL_POWEROFF=y CONFIG_BUILTIN=y CONFIG_CLK=y diff --git a/boards/sim/sim/sim/src/sim_bringup.c b/boards/sim/sim/sim/src/sim_bringup.c index d0b4a099b3..bc94be89e3 100644 --- a/boards/sim/sim/sim/src/sim_bringup.c +++ b/boards/sim/sim/sim/src/sim_bringup.c @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -93,6 +95,9 @@ int sim_bringup(void) #ifdef CONFIG_RAMMTD uint8_t *ramstart; #endif +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_BLK_RPMSG_SERVER) + uint8_t *ramdiskstart; +#endif #ifdef CONFIG_SIM_I2CBUS struct i2c_master_s *i2cbus; #endif @@ -231,6 +236,16 @@ int sim_bringup(void) } #endif +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_BLK_RPMSG_SERVER) + ramdiskstart = (uint8_t *)kmm_malloc(512 * 2048); + ret = ramdisk_register(1, ramdiskstart, 2048, 512, + RDFLAG_WRENABLED | RDFLAG_FUNLINK); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register ramdisk: %d\n", ret); + } +#endif + #ifdef CONFIG_ONESHOT /* Get an instance of the simulated oneshot timer */ @@ -443,6 +458,10 @@ int sim_bringup(void) rpmsgdev_register("server", "/dev/ttyUSB0", "/dev/ttyUSB0"); #endif +#ifdef CONFIG_BLK_RPMSG + rpmsgblk_register("server", "/dev/ram1", NULL); +#endif + #ifdef CONFIG_RPMSGMTD rpmsgmtd_register("server", "/dev/rammtd", NULL); #endif diff --git a/drivers/drivers_initialize.c b/drivers/drivers_initialize.c index 085c50a435..5cccfd7d64 100644 --- a/drivers/drivers_initialize.c +++ b/drivers/drivers_initialize.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -169,6 +170,10 @@ void drivers_initialize(void) rpmsgdev_server_init(); #endif +#ifdef CONFIG_BLK_RPMSG_SERVER + rpmsgblk_server_init(); +#endif + #ifdef CONFIG_RPMSGMTD_SERVER rpmsgmtd_server_init(); #endif diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 95be70c993..16a828f76f 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -34,6 +34,16 @@ config DRVR_MKRD the selecting this option will also enable the BOARDIOC_MKRD command that will support creation of RAM disks from applications. +config BLK_RPMSG + bool "RPMSG Block Client Support" + default n + depends on RPTUN + +config BLK_RPMSG_SERVER + bool "RPMSG Block Server Support" + default n + depends on RPTUN + # ARCH needs to support memory access while CPU is running to be able to use # the LWL CONSOLE diff --git a/drivers/misc/Make.defs b/drivers/misc/Make.defs index 30ef53ec16..b558650f84 100644 --- a/drivers/misc/Make.defs +++ b/drivers/misc/Make.defs @@ -55,6 +55,14 @@ ifeq ($(CONFIG_DEV_RPMSG_SERVER),y) CSRCS += rpmsgdev_server.c endif +ifeq ($(CONFIG_BLK_RPMSG),y) + CSRCS += rpmsgblk.c +endif + +ifeq ($(CONFIG_BLK_RPMSG_SERVER),y) + CSRCS += rpmsgblk_server.c +endif + # Include build support DEPPATH += --dep-path misc diff --git a/drivers/misc/rpmsgblk.c b/drivers/misc/rpmsgblk.c new file mode 100644 index 0000000000..e88ecbba4a --- /dev/null +++ b/drivers/misc/rpmsgblk.c @@ -0,0 +1,1106 @@ +/**************************************************************************** + * drivers/misc/rpmsgblk.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 +#include +#include +#include +#include + +#include "rpmsgblk.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rpmsgblk_s +{ + struct block_operations blk; /* Rpmsg-Block device operation */ + struct rpmsg_endpoint ept; /* Rpmsg endpoint */ + FAR const char *remotecpu; /* The server cpu name */ + FAR const char *remotepath; /* The device path in the server cpu */ + sem_t wait; /* Wait sem, used for preventing any + * opreation until the connection + * between two cpu established. + */ + mutex_t lock; /* Lock for thread-safe */ + struct geometry geo; /* block geomerty */ + int refs; /* refence count */ +}; + +/* Rpmsg device cookie used to handle the response from the remote cpu */ + +struct rpmsgblk_cookie_s +{ + sem_t sem; /* Semaphore used fo rpmsg */ + int result; /* The return value of the remote call */ + FAR void *data; /* The return data buffer of the remote call */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* The block operation functions */ + +static int rpmsgblk_open(FAR struct inode *inode); +static int rpmsgblk_close(FAR struct inode *inode); +static ssize_t rpmsgblk_read(FAR struct inode *inode, + FAR unsigned char *buffer, + blkcnt_t start_sector, unsigned int nsectors); +static ssize_t rpmsgblk_write(FAR struct inode *inode, + FAR const unsigned char *buffer, + blkcnt_t start_sector, unsigned int nsectors); +static int rpmsgblk_geometry(FAR struct inode *inode, + FAR struct geometry *geometry); +static size_t rpmsgblk_ioctl_arglen(int cmd); +static int rpmsgblk_ioctl(FAR struct inode *inode, int cmd, + unsigned long arg); +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static int rpmsgblk_unlink(FAR struct inode *inode); +#endif + +/* Functions for sending data to the remote cpu */ + +static int rpmsgblk_send_recv(FAR struct rpmsgblk_s *priv, + uint32_t command, bool copy, + FAR struct rpmsgblk_header_s *msg, + int len, FAR void *data); +static FAR void *rpmsgblk_get_tx_payload_buffer(FAR struct rpmsgblk_s *priv, + FAR uint32_t *len); + +/* Functions handle the responses from the remote cpu */ + +static int rpmsgblk_default_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_read_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_geometry_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_ioctl_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); + +/* Functions for creating communication with remote cpu */ + +static void rpmsgblk_device_created(struct rpmsg_device *rdev, + FAR void *priv_); +static void rpmsgblk_device_destroy(struct rpmsg_device *rdev, + FAR void *priv_); +static int rpmsgblk_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv); +static void rpmsgblk_ns_bound(struct rpmsg_endpoint *ept); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Rpmsg device response handler table */ + +static const rpmsg_ept_cb g_rpmsgblk_handler[] = +{ + [RPMSGBLK_OPEN] = rpmsgblk_default_handler, + [RPMSGBLK_CLOSE] = rpmsgblk_default_handler, + [RPMSGBLK_READ] = rpmsgblk_read_handler, + [RPMSGBLK_WRITE] = rpmsgblk_default_handler, + [RPMSGBLK_GEOMETRY] = rpmsgblk_geometry_handler, + [RPMSGBLK_IOCTL] = rpmsgblk_ioctl_handler, + [RPMSGBLK_UNLINK] = rpmsgblk_default_handler, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rpmsgblk_open + * + * Description: + * Rpmsg-blk open operation + * + * Parameters: + * inode + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int rpmsgblk_open(FAR struct inode *inode) +{ + FAR struct rpmsgblk_s *priv = (FAR struct rpmsgblk_s *)inode->i_private; + struct rpmsgblk_open_s msg; + int ret; + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + ferr("lock failed, ret=%d\n", ret); + return ret; + } + + /* Check if this is the first time that the driver has been opened. */ + + if (priv->refs++ == 0) + { + /* Try to open the block device in the remote cpu */ + + ret = rpmsgblk_send_recv(priv, RPMSGBLK_OPEN, true, &msg.header, + sizeof(msg), NULL); + if (ret < 0) + { + ferr("open failed, ret=%d\n", ret); + priv->refs--; + } + } + + nxmutex_unlock(&priv->lock); + return ret; +} + +/**************************************************************************** + * Name: rpmsgblk_close + * + * Description: + * Rpmsg-blk close operation + * + * Parameters: + * inode + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int rpmsgblk_close(FAR struct inode *inode) +{ + FAR struct rpmsgblk_s *priv = (FAR struct rpmsgblk_s *)inode->i_private; + struct rpmsgblk_close_s msg; + int ret; + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + ferr("lock failed, ret=%d\n", ret); + return ret; + } + + /* There are no more references to the port */ + + if (--priv->refs == 0) + { + ret = rpmsgblk_send_recv(priv, RPMSGBLK_CLOSE, true, &msg.header, + sizeof(msg), NULL); + if (ret < 0) + { + ferr("close failed, ret=%d\n", ret); + priv->refs++; + } + } + + nxmutex_unlock(&priv->lock); + return ret; +} + +/**************************************************************************** + * Name: rpmsgblk_read + * + * Description: + * Rpmsg-blk read operation + * + * Parameters: + * dev - the blk device + * offset - read offset address in the blk device + * nbytes - read number in bytes + * buffer - read buffer + * + * Returned Values: + * The positive non-zero number of bytes read on success, 0 on if an + * end-of-file condition, or a negated errno value on any failure. + * + ****************************************************************************/ + +static ssize_t rpmsgblk_read(FAR struct inode *inode, + FAR unsigned char *buffer, + blkcnt_t start_sector, unsigned int nsectors) +{ + FAR struct rpmsgblk_s *priv = (FAR struct rpmsgblk_s *)inode->i_private; + struct rpmsgblk_read_s msg; + struct iovec iov; + int ret; + + if (buffer == NULL) + { + return -EINVAL; + } + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + ret = rpmsgblk_geometry(inode, &priv->geo); + if (ret < 0) + { + ferr("Get geometry failed, ret=%d\n", ret); + return ret; + } + + /* In block read, iov_len represent the received block number */ + + iov.iov_base = buffer; + iov.iov_len = 0; + + msg.startsector = start_sector; + msg.nsectors = nsectors; + msg.sectorsize = priv->geo.geo_sectorsize; + + ret = rpmsgblk_send_recv(priv, RPMSGBLK_READ, true, &msg.header, + sizeof(msg) - 1, &iov); + + return ret < 0 ? ret : iov.iov_len; +} + +/**************************************************************************** + * Name: rpmsgblk_write + * + * Description: + * Rpmsg-blk write operation + * + * Parameters: + * dev - the blk device + * offset - write offset address in the blk device + * nbytes - write number in bytes + * buffer - write buffer + * + * Returned Values: + * On success, the number of bytes written are returned (zero indicates + * nothing was written). On any failure, a negated errno value is returned + * (see comments withwrite() for a description of the appropriate errno + * values). + * + ****************************************************************************/ + +static ssize_t rpmsgblk_write(FAR struct inode *inode, + FAR const unsigned char *buffer, + blkcnt_t start_sector, unsigned int nsectors) +{ + FAR struct rpmsgblk_s *priv = (FAR struct rpmsgblk_s *)inode->i_private; + FAR struct rpmsgblk_write_s *msg; + struct rpmsgblk_cookie_s cookie; + uint32_t sectorsize; + uint32_t space; + size_t written = 0; + int ret; + + if (buffer == NULL) + { + return -EINVAL; + } + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + ret = rpmsgblk_geometry(inode, &priv->geo); + if (ret < 0) + { + ferr("Get geometry failed, ret=%d\n", ret); + return ret; + } + + /* Perform the rpmsg write */ + + memset(&cookie, 0, sizeof(cookie)); + nxsem_init(&cookie.sem, 0, 0); + + sectorsize = priv->geo.geo_sectorsize; + while (written < nsectors) + { + msg = rpmsgblk_get_tx_payload_buffer(priv, &space); + if (msg == NULL) + { + ret = -ENOMEM; + goto out; + } + + DEBUGASSERT(sizeof(*msg) - 1 + sectorsize <= space); + + msg->nsectors = (space - sizeof(*msg) + 1) / sectorsize; + if (msg->nsectors >= nsectors - written) + { + /* Send complete, set cookie is valid, need ack */ + + msg->nsectors = nsectors - written; + msg->header.cookie = (uintptr_t)&cookie; + } + else + { + /* Not send complete, set cookie invalid, do not need ack */ + + msg->header.cookie = 0; + } + + msg->header.command = RPMSGBLK_WRITE; + msg->header.result = -ENXIO; + msg->startsector = start_sector; + msg->sectorsize = sectorsize; + memcpy(msg->buf, buffer, msg->nsectors * sectorsize); + + buffer += msg->nsectors * sectorsize; + start_sector += msg->nsectors; + written += msg->nsectors; + + ret = rpmsg_send_nocopy(&priv->ept, msg, + sizeof(*msg) - 1 + msg->nsectors * sectorsize); + if (ret < 0) + { + goto out; + } + } + + ret = rpmsg_wait(&priv->ept, &cookie.sem); + if (ret < 0) + { + goto out; + } + + ret = cookie.result; + +out: + nxsem_destroy(&cookie.sem); + return ret < 0 ? ret : nsectors; +} + +/**************************************************************************** + * Name: rpmsgblk_geometry + * + * Description: + * Rpmsg-blk geometry operation + * + * Parameters: + * inode - the blk device inode + * geometry - pointer to the application geomoetry struct + * + * Returned Values: + * On success, the number of bytes written are returned (zero indicates + * nothing was written). On any failure, a negated errno value is returned + * (see comments withwrite() for a description of the appropriate errno + * values). + * + ****************************************************************************/ + +static int rpmsgblk_geometry(FAR struct inode *inode, + FAR struct geometry *geometry) +{ + FAR struct rpmsgblk_s *priv = (FAR struct rpmsgblk_s *)inode->i_private; + struct rpmsgblk_geometry_s *msg; + uint32_t space; + int msglen; + int ret; + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Return the perviously got geometry */ + + if (priv->geo.geo_sectorsize != 0) + { + memcpy(geometry, &priv->geo, sizeof(*geometry)); + goto out; + } + + msglen = sizeof(*msg) + sizeof(*geometry) - 1; + + msg = rpmsgblk_get_tx_payload_buffer(priv, &space); + if (msg == NULL) + { + ret = -ENOMEM; + goto out; + } + + DEBUGASSERT(space > msglen); + + msg->arg = (uintptr_t)geometry; + msg->arglen = sizeof(*geometry); + memcpy(msg->buf, geometry, sizeof(*geometry)); + + ret = rpmsgblk_send_recv(priv, RPMSGBLK_GEOMETRY, false, &msg->header, + msglen, geometry); + if (ret >= 0) + { + memcpy(&priv->geo, geometry, sizeof(priv->geo)); + } + +out: + nxmutex_unlock(&priv->lock); + return ret; +} + +/**************************************************************************** + * Name: rpmsgblk_ioctl_arglen + * + * Description: + * Get rpmsg blk ioctl argument length according to the command + * + * Parameters: + * cmd - the ioctl command + * + * Returned Values: + * 0 - ioctl command not support + * positive - the argument length + * + ****************************************************************************/ + +static size_t rpmsgblk_ioctl_arglen(int cmd) +{ + switch (cmd) + { + case BIOC_XIPBASE: + return sizeof(uintptr_t); + case BIOC_PROBE: + case BIOC_EJECT: + case BIOC_LLFORMAT: + case BIOC_GETFORMAT: + case BIOC_ALLOCSECT: + case BIOC_FREESECT: + case BIOC_FLUSH: + return 0; + case BIOC_READSECT: + case BIOC_WRITESECT: + return sizeof(struct smart_read_write_s); + case BIOC_GETPROCFSD: + return sizeof(struct mtd_smart_procfs_data_s); + case BIOC_DEBUGCMD: + return sizeof(struct mtd_smart_debug_data_s); + case BIOC_GEOMETRY: + return sizeof(struct geometry); + case BIOC_PARTINFO: + return sizeof(struct partition_info_s); + case BIOC_BLKSSZGET: + return sizeof(blksize_t); + default: + return 0; + } +} + +/**************************************************************************** + * Name: rpmsgblk_ioctl + * + * Description: + * Rpmsg-blk ioctl operation + * + * Parameters: + * inode - the blk device inode + * cmd - the ioctl command + * arg - the ioctl arguments + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int rpmsgblk_ioctl(FAR struct inode *inode, int cmd, + unsigned long arg) +{ + FAR struct rpmsgblk_s *priv = (FAR struct rpmsgblk_s *)inode->i_private; + FAR struct rpmsgblk_ioctl_s *msg; + uint32_t space; + size_t arglen; + size_t msglen; + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + /* Call our internal routine to perform the ioctl */ + + arglen = rpmsgblk_ioctl_arglen(cmd); + msglen = sizeof(*msg) + arglen - 1; + + msg = rpmsgblk_get_tx_payload_buffer(priv, &space); + if (msg == NULL) + { + return -ENOMEM; + } + + msg->request = cmd; + msg->arg = arg; + msg->arglen = arglen; + + if (arglen > 0) + { + memcpy(msg->buf, (FAR void *)(uintptr_t)arg, arglen); + } + + return rpmsgblk_send_recv(priv, RPMSGBLK_IOCTL, false, &msg->header, + msglen, arglen > 0 ? (FAR void *)arg : NULL); +} + +/**************************************************************************** + * Name: rpmsgblk_unlink + * + * Description: + * Rpmsg-blk ioctl operation + * + * Parameters: + * inode - the blk device inode + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static int rpmsgblk_unlink(FAR struct inode *inode) +{ + FAR struct rpmsgblk_s *priv = (FAR struct rpmsgblk_s *)inode->i_private; + struct rpmsgblk_unlink_s msg; + int ret; + + ret = rpmsgblk_send_recv(priv, RPMSGBLK_UNLINK, true, &msg.header, + sizeof(msg), NULL); + if (ret < 0) + { + ferr("unlink failed, ret=%d\n", ret); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: rpmsgblk_get_tx_payload_buffer + * + * Description: + * Get the rpmsg blk tx payload, the buffer is from the rpmsg share memory + * that can be accessed by local and remote cpu. + * + * Parameters: + * priv - The rpmsg-blk handle + * len - The got memroy size + * + * Returned Values: + * NULL - failure + * not NULL - success + * + ****************************************************************************/ + +static FAR void *rpmsgblk_get_tx_payload_buffer(FAR struct rpmsgblk_s *priv, + FAR uint32_t *len) +{ + int sval; + + nxsem_get_value(&priv->wait, &sval); + if (sval <= 0) + { + rpmsg_wait(&priv->ept, &priv->wait); + rpmsg_post(&priv->ept, &priv->wait); + } + + return rpmsg_get_tx_payload_buffer(&priv->ept, len, true); +} + +/**************************************************************************** + * Name: rpmsgblk_send_recv + * + * Description: + * Send and receive the rpmsg data. + * + * Parameters: + * priv - rpmsg blk handle + * command - the command, RPMSGBLK_OPEN, RPMSGBLK_CLOSE, RPMSGBLK_READ, + * RPMSGBLK_WRITE, RPMSGBLK_IOCTL + * copy - true, send a message across to the remote processor, and the + * tx buffer will be alloced inside function rpmsg_send() + * false, send a message in tx buffer reserved by + * rpmsg_get_tx_payload_buffer() across to the remote + * processor. + * msg - the message header + * len - length of the payload + * data - the data + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int rpmsgblk_send_recv(FAR struct rpmsgblk_s *priv, + uint32_t command, bool copy, + FAR struct rpmsgblk_header_s *msg, + int len, FAR void *data) +{ + struct rpmsgblk_cookie_s cookie; + int ret; + + memset(&cookie, 0, sizeof(cookie)); + nxsem_init(&cookie.sem, 0, 0); + + if (data != NULL) + { + cookie.data = data; + } + else if (copy) + { + cookie.data = msg; + } + + msg->command = command; + msg->result = -ENXIO; + msg->cookie = (uintptr_t)&cookie; + + if (copy) + { + ret = rpmsg_send(&priv->ept, msg, len); + } + else + { + ret = rpmsg_send_nocopy(&priv->ept, msg, len); + } + + if (ret < 0) + { + goto fail; + } + + ret = rpmsg_wait(&priv->ept, &cookie.sem); + if (ret >= 0) + { + ret = cookie.result; + } + +fail: + nxsem_destroy(&cookie.sem); + return ret; +} + +/**************************************************************************** + * Name: rpmsgblk_default_handler + * + * Description: + * Default rpmsg-blk response handler, this function will be called to + * process the return message of rpmsgblk_open(), rpmsgblk_close() and + * rpmsgblk_write(). + * + * Parameters: + * ept - The rpmsg endpoint + * data - The return message + * len - The return message length + * src - unknow + * priv - unknow + * + * Returned Values: + * Always OK + * + ****************************************************************************/ + +static int rpmsgblk_default_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_header_s *header = data; + FAR struct rpmsgblk_cookie_s *cookie = + (FAR struct rpmsgblk_cookie_s *)(uintptr_t)header->cookie; + + cookie->result = header->result; + if (cookie->result >= 0 && cookie->data) + { + memcpy(cookie->data, data, len); + } + + return rpmsg_post(ept, &cookie->sem); +} + +/**************************************************************************** + * Name: rpmsgblk_read_handler + * + * Description: + * Rpmsg-blk block read response handler, this function will be called to + * process the return message of rpmsgblk_bread(). + * + * Parameters: + * ept - The rpmsg endpoint + * data - The return message + * len - The return message length + * src - unknow + * priv - unknow + * + * Returned Values: + * Always OK + * + ****************************************************************************/ + +static int rpmsgblk_read_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_header_s *header = data; + FAR struct rpmsgblk_cookie_s *cookie = + (FAR struct rpmsgblk_cookie_s *)(uintptr_t)header->cookie; + FAR struct rpmsgblk_read_s *rsp = data; + FAR struct iovec *iov = cookie->data; + size_t read; + + cookie->result = header->result; + if (cookie->result > 0) + { + read = cookie->result * rsp->sectorsize; + memcpy(iov->iov_base, rsp->buf, read); + iov->iov_base += read; + iov->iov_len += cookie->result; + } + + if (cookie->result <= 0 || iov->iov_len >= rsp->nsectors) + { + return rpmsg_post(ept, &cookie->sem); + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgblk_geometry_handler + * + * Description: + * Rpmsg-blk geometry response handler, this function will be called to + * process the return message of rpmsgblk_geometry(). + * + * Parameters: + * ept - The rpmsg endpoint + * data - The return message + * len - The return message length + * src - unknow + * priv - unknow + * + * Returned Values: + * Always OK + * + ****************************************************************************/ + +static int rpmsgblk_geometry_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_header_s *header = data; + FAR struct rpmsgblk_cookie_s *cookie = + (FAR struct rpmsgblk_cookie_s *)(uintptr_t)header->cookie; + FAR struct rpmsgblk_geometry_s *rsp = data; + + if (cookie->result >= 0 && rsp->arglen > 0) + { + memcpy(cookie->data, rsp->buf, rsp->arglen); + } + + return rpmsg_post(ept, &cookie->sem); +} + +/**************************************************************************** + * Name: rpmsgblk_ioctl_handler + * + * Description: + * Rpmsg-blk ioctl response handler, this function will be called to + * process the return message of rpmsgblk_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 rpmsgblk_ioctl_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_header_s *header = data; + FAR struct rpmsgblk_cookie_s *cookie = + (FAR struct rpmsgblk_cookie_s *)(uintptr_t)header->cookie; + FAR struct rpmsgblk_ioctl_s *rsp = data; + + if (cookie->result >= 0 && rsp->arglen > 0) + { + memcpy(cookie->data, rsp->buf, rsp->arglen); + } + + return rpmsg_post(ept, &cookie->sem); +} + +/**************************************************************************** + * Name: rpmsgblk_ns_bound + * + * Description: + * Rpmsg blk end point service bound callback function , called when + * remote end point address is received. + * + * Parameters: + * ept - The rpmsg-blk end point + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void rpmsgblk_ns_bound(FAR struct rpmsg_endpoint *ept) +{ + FAR struct rpmsgblk_s *priv = ept->priv; + + rpmsg_post(&priv->ept, &priv->wait); +} + +/**************************************************************************** + * Name: rpmsgblk_device_created + * + * Description: + * Rpmsg blk create function, this function will be called by rptun to + * create a rpmsg-blk end point. + * + * Parameters: + * rdev - The rpmsg-blk end point + * priv_ - Rpmsg-blk handle + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void rpmsgblk_device_created(FAR struct rpmsg_device *rdev, + FAR void *priv_) +{ + FAR struct rpmsgblk_s *priv = priv_; + char buf[RPMSG_NAME_SIZE]; + + if (strcmp(priv->remotecpu, rpmsg_get_cpuname(rdev)) == 0) + { + priv->ept.priv = priv; + priv->ept.ns_bound_cb = rpmsgblk_ns_bound; + snprintf(buf, sizeof(buf), "%s%s", RPMSGBLK_NAME_PREFIX, + priv->remotepath); + rpmsg_create_ept(&priv->ept, rdev, buf, + RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, + rpmsgblk_ept_cb, NULL); + } +} + +/**************************************************************************** + * Name: rpmsgblk_device_destroy + * + * Description: + * Rpmsg blk destroy function, this function will be called by rptun to + * destroy rpmsg-blk end point. + * + * Parameters: + * rdev - The rpmsg-blk end point + * priv_ - Rpmsg-blk handle + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void rpmsgblk_device_destroy(FAR struct rpmsg_device *rdev, + FAR void *priv_) +{ + FAR struct rpmsgblk_s *priv = priv_; + + if (strcmp(priv->remotecpu, rpmsg_get_cpuname(rdev)) == 0) + { + rpmsg_destroy_ept(&priv->ept); + } +} + +/**************************************************************************** + * Name: rpmsgblk_ept_cb + * + * Description: + * Rpmsg blk end point callback function, this function will be called + * when receive the remote cpu message. + * + * Parameters: + * ept - The rpmsg-blk 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 rpmsgblk_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv) +{ + FAR struct rpmsgblk_header_s *header = data; + uint32_t command = header->command; + + if (command < ARRAY_SIZE(g_rpmsgblk_handler)) + { + return g_rpmsgblk_handler[command](ept, data, len, src, priv); + } + + return -EINVAL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rpmsgblk_register + * + * Description: + * Rpmsg-blk client initialize function, the client cpu should call + * this function in the board initialize process. + * + * Parameters: + * remotecpu - the server cpu name + * remotepath - the device you want to access in the remote cpu + * localpath - the device path in local cpu, if NULL, the localpath is + * same as the remotepath, provide this argument to supoort + * custom device path + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +int rpmsgblk_register(FAR const char *remotecpu, FAR const char *remotepath, + FAR const char *localpath) +{ + FAR struct rpmsgblk_s *dev; + int ret; + + /* Arguments check */ + + if (remotecpu == NULL || remotepath == NULL) + { + ferr("ERROR: Input arguments null\n"); + return -EINVAL; + } + + /* Create an instance of the RPMSG MTD device */ + + dev = kmm_zalloc(sizeof(*dev)); + if (dev == NULL) + { + ferr("ERROR: Failed to allocate the RPMSG MTD degice\n"); + return -ENOMEM; + } + + /* Perform initialization as necessary. (unsupported methods were + * nullified by kmm_zalloc). + */ + + dev->blk.open = rpmsgblk_open; + dev->blk.close = rpmsgblk_close; + dev->blk.read = rpmsgblk_read; + dev->blk.write = rpmsgblk_write; + dev->blk.geometry = rpmsgblk_geometry; + dev->blk.ioctl = rpmsgblk_ioctl; +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + dev->blk.unlink = rpmsgblk_unlink; +#endif + + /* Initialize the rpmsg device */ + + dev->remotecpu = remotecpu; + dev->remotepath = remotepath; + + nxsem_init(&dev->wait, 0, 0); + nxmutex_init(&dev->lock); + + /* Register the rpmsg callback */ + + ret = rpmsg_register_callback(dev, + rpmsgblk_device_created, + rpmsgblk_device_destroy, + NULL, + NULL); + if (ret < 0) + { + ferr("ERROR: register callback failed, ret=%d\n", ret); + goto fail; + } + + /* Register driver, using the remotepath if localpath is NULL */ + + if (localpath == NULL) + { + localpath = remotepath; + } + + ret = register_blockdriver(localpath, &dev->blk, 0755, dev); + if (ret < 0) + { + ferr("ERROR: register driver failed, ret=%d\n", ret); + goto fail_with_rpmsg; + } + + return OK; + +fail_with_rpmsg: + rpmsg_unregister_callback(dev, + rpmsgblk_device_created, + rpmsgblk_device_destroy, + NULL, + NULL); + +fail: + nxsem_destroy(&dev->wait); + nxmutex_destroy(&dev->lock); + kmm_free(dev); + return ret; +} diff --git a/drivers/misc/rpmsgblk.h b/drivers/misc/rpmsgblk.h new file mode 100644 index 0000000000..84d609e9d6 --- /dev/null +++ b/drivers/misc/rpmsgblk.h @@ -0,0 +1,109 @@ +/**************************************************************************** + * drivers/misc/rpmsgblk.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_MISC_RPMSGBLK_H +#define __DRIVERS_MISC_RPMSGBLK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#define RPMSGBLK_NAME_PREFIX "rpmsgblk-" +#define RPMSGBLK_NAME_PREFIX_LEN 9 + +#define RPMSGBLK_OPEN 1 +#define RPMSGBLK_CLOSE 2 +#define RPMSGBLK_READ 3 +#define RPMSGBLK_WRITE 4 +#define RPMSGBLK_GEOMETRY 5 +#define RPMSGBLK_IOCTL 6 +#define RPMSGBLK_UNLINK 7 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +begin_packed_struct struct rpmsgblk_header_s +{ + uint32_t command; + int32_t result; + uint64_t cookie; +} end_packed_struct; + +begin_packed_struct struct rpmsgblk_open_s +{ + struct rpmsgblk_header_s header; +} end_packed_struct; + +#define rpmsgblk_close_s rpmsgblk_open_s + +begin_packed_struct struct rpmsgblk_read_s +{ + struct rpmsgblk_header_s header; + uint32_t startsector; + uint32_t nsectors; + int32_t sectorsize; + uint32_t count; + char buf[1]; +} end_packed_struct; + +#define rpmsgblk_write_s rpmsgblk_read_s + +begin_packed_struct struct rpmsgblk_geometry_s +{ + struct rpmsgblk_header_s header; + uint64_t arg; + uint32_t arglen; + char buf[1]; +} end_packed_struct; + +begin_packed_struct struct rpmsgblk_ioctl_s +{ + struct rpmsgblk_header_s header; + uint64_t arg; + uint32_t arglen; + int32_t request; + char buf[1]; +} end_packed_struct; + +begin_packed_struct struct rpmsgblk_unlink_s +{ + struct rpmsgblk_header_s header; +} end_packed_struct; + +/**************************************************************************** + * Internal function prototypes + ****************************************************************************/ + +/**************************************************************************** + * Internal data + ****************************************************************************/ + +#endif /* __DRIVERS_MISC_RPMSGBLK_H */ diff --git a/drivers/misc/rpmsgblk_server.c b/drivers/misc/rpmsgblk_server.c new file mode 100644 index 0000000000..2ef9cde8a9 --- /dev/null +++ b/drivers/misc/rpmsgblk_server.c @@ -0,0 +1,402 @@ +/**************************************************************************** + * drivers/misc/rpmsgblk_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 "rpmsgblk.h" + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rpmsgblk_server_s +{ + struct rpmsg_endpoint ept; + FAR struct inode *blknode; + FAR const struct block_operations *bops; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Functions handle the messages from the client cpu */ + +static int rpmsgblk_open_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_close_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_read_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_write_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_geometry_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_ioctl_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgblk_unlink_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); + +/* Functions for creating communication with client cpu */ + +static bool rpmsgblk_ns_match(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest); +static void rpmsgblk_ns_bind(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest); +static void rpmsgblk_ns_unbind(FAR struct rpmsg_endpoint *ept); +static int rpmsgblk_ept_cb(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_rpmsgblk_handler[] = +{ + [RPMSGBLK_OPEN] = rpmsgblk_open_handler, + [RPMSGBLK_CLOSE] = rpmsgblk_close_handler, + [RPMSGBLK_READ] = rpmsgblk_read_handler, + [RPMSGBLK_WRITE] = rpmsgblk_write_handler, + [RPMSGBLK_GEOMETRY] = rpmsgblk_geometry_handler, + [RPMSGBLK_IOCTL] = rpmsgblk_ioctl_handler, + [RPMSGBLK_UNLINK] = rpmsgblk_unlink_handler, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rpmsgblk_open_handler + ****************************************************************************/ + +static int rpmsgblk_open_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_server_s *server = ept->priv; + FAR struct rpmsgblk_open_s *msg = data; + + if (server->blknode != NULL) + { + msg->header.result = -EBUSY; + goto out; + } + + msg->header.result = open_blockdriver(&ept->name[RPMSGBLK_NAME_PREFIX_LEN], + 0, &server->blknode); + if (msg->header.result < 0) + { + ferr("block device open failed, ret=%d\n", msg->header.result); + goto out; + } + + server->bops = server->blknode->u.i_bops; + +out: + return rpmsg_send(ept, msg, sizeof(*msg)); +} + +/**************************************************************************** + * Name: rpmsgblk_close_handler + ****************************************************************************/ + +static int rpmsgblk_close_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_server_s *server = ept->priv; + FAR struct rpmsgblk_close_s *msg = data; + + msg->header.result = close_blockdriver(server->blknode); + if (msg->header.result < 0) + { + ferr("block device close failed, ret=%d\n", msg->header.result); + goto out; + } + + server->bops = NULL; + server->blknode = NULL; + +out: + return rpmsg_send(ept, msg, sizeof(*msg)); +} + +/**************************************************************************** + * Name: rpmsgblk_read_handler + ****************************************************************************/ + +static int rpmsgblk_read_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_server_s *server = ept->priv; + FAR struct rpmsgblk_read_s *msg = data; + FAR struct rpmsgblk_read_s *rsp; + int ret = -ENOENT; + size_t read = 0; + size_t nsectors; + uint32_t space; + + while (read < msg->nsectors) + { + rsp = rpmsg_get_tx_payload_buffer(ept, &space, true); + if (rsp == NULL) + { + ferr("get tx payload failed or no enough space\n"); + return -ENOMEM; + } + + DEBUGASSERT(space >= sizeof(*msg) - 1 + msg->sectorsize); + + *rsp = *msg; + + nsectors = (space - sizeof(*msg) + 1) / msg->sectorsize; + if (nsectors > msg->nsectors - read) + { + nsectors = msg->nsectors - read; + } + + ret = server->bops->read(server->blknode, (unsigned char *)rsp->buf, + msg->startsector, msg->nsectors); + rsp->header.result = ret; + rpmsg_send_nocopy(ept, rsp, (ret < 0 ? 0 : ret * msg->sectorsize) + + sizeof(*rsp) - 1); + if (ret <= 0) + { + ferr("mtd block read failed\n"); + break; + } + + read += ret; + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgblk_write_handler + ****************************************************************************/ + +static int rpmsgblk_write_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_server_s *server = ept->priv; + FAR struct rpmsgblk_write_s *msg = data; + int ret; + + ret = server->bops->write(server->blknode, (FAR unsigned char *)msg->buf, + msg->startsector, msg->nsectors); + if (ret <= 0) + { + ferr("mtd block write failed\n"); + } + + /* cookie != 0 indicate the data has been sent complete, so send back + * the total written blocks. + */ + + if (msg->header.cookie != 0) + { + msg->header.result = ret; + return rpmsg_send(ept, msg, sizeof(*msg) - 1); + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgblk_ioctl_handler + ****************************************************************************/ + +static int rpmsgblk_geometry_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_server_s *server = ept->priv; + FAR struct rpmsgblk_geometry_s *msg = data; + + DEBUGASSERT(msg->arglen == sizeof(struct geometry)); + + msg->header.result = server->bops->geometry( + server->blknode, (FAR struct geometry *)msg->buf); + + return rpmsg_send(ept, msg, len); +} + +/**************************************************************************** + * Name: rpmsgblk_ioctl_handler + ****************************************************************************/ + +static int rpmsgblk_ioctl_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_server_s *server = ept->priv; + FAR struct rpmsgblk_ioctl_s *msg = data; + + msg->header.result = server->bops->ioctl(server->blknode, msg->request, + msg->arglen > 0 ? + (unsigned long)msg->buf : + msg->arg); + + return rpmsg_send(ept, msg, len); +} + +/**************************************************************************** + * Name: rpmsgblk_unlink_handler + ****************************************************************************/ + +static int rpmsgblk_unlink_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgblk_server_s *server = ept->priv; + FAR struct rpmsgblk_unlink_s *msg = data; + + msg->header.result = server->bops->unlink(server->blknode); + + return rpmsg_send(ept, msg, len); +} + +/**************************************************************************** + * Name: rpmsgblk_ns_match + ****************************************************************************/ + +static bool rpmsgblk_ns_match(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest) +{ + return !strncmp(name, RPMSGBLK_NAME_PREFIX, RPMSGBLK_NAME_PREFIX_LEN); +} + +/**************************************************************************** + * Name: rpmsgblk_ns_bind + ****************************************************************************/ + +static void rpmsgblk_ns_bind(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest) +{ + FAR struct rpmsgblk_server_s *server; + int ret; + + server = kmm_zalloc(sizeof(*server)); + if (server == NULL) + { + ferr("mtd server malloced failed\n"); + return; + } + + server->ept.priv = server; + + ret = rpmsg_create_ept(&server->ept, rdev, name, + RPMSG_ADDR_ANY, dest, + rpmsgblk_ept_cb, rpmsgblk_ns_unbind); + if (ret < 0) + { + ferr("endpoint create failed, ret=%d\n", ret); + kmm_free(server); + } +} + +/**************************************************************************** + * Name: rpmsgblk_ns_unbind + ****************************************************************************/ + +static void rpmsgblk_ns_unbind(FAR struct rpmsg_endpoint *ept) +{ + FAR struct rpmsgblk_server_s *server = ept->priv; + + rpmsg_destroy_ept(&server->ept); + kmm_free(server); +} + +/**************************************************************************** + * Name: rpmsgblk_ept_cb + ****************************************************************************/ + +static int rpmsgblk_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv) +{ + FAR struct rpmsgblk_header_s *header = data; + uint32_t command = header->command; + + if (command < ARRAY_SIZE(g_rpmsgblk_handler)) + { + return g_rpmsgblk_handler[command](ept, data, len, src, priv); + } + + return -EINVAL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rpmsgblk_server_init + * + * Description: + * Rpmsg-mtd server initialize function, the server cpu should call + * this function. + * + * Parameters: + * None + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +int rpmsgblk_server_init(void) +{ + return rpmsg_register_callback(NULL, + NULL, + NULL, + rpmsgblk_ns_match, + rpmsgblk_ns_bind); +} diff --git a/include/nuttx/drivers/rpmsgblk.h b/include/nuttx/drivers/rpmsgblk.h new file mode 100644 index 0000000000..3ee2a20056 --- /dev/null +++ b/include/nuttx/drivers/rpmsgblk.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * include/nuttx/drivers/rpmsgblk.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_DRIVERS_RPMSGBLK_H +#define __INCLUDE_NUTTX_DRIVERS_RPMSGBLK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: rpmsgblk_server_init + * + * Description: + * Rpmsg-device server initialize function, the server cpu should call + * this function. + * + * Parameters: + * None + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_BLK_RPMSG_SERVER +int rpmsgblk_server_init(void); +#endif + +/**************************************************************************** + * Name: rpmsgblk_register + * + * Description: + * Rpmsg-device client initialize function, the client cpu should call + * this function in the board initialize process. + * + * Parameters: + * remotecpu - the server cpu name + * remotepath - the device you want to access in the remote cpu + * localpath - the device path in local cpu, if NULL, the localpath is + * same as the remotepath, provide this argument to supoort + * custom device path + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_BLK_RPMSG +int rpmsgblk_register(FAR const char *remotecpu, FAR const char *remotepath, + FAR const char *localpath); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __INCLUDE_NUTTX_DRIVERS_RPMSGDEV_H */