diff --git a/boards/sim/sim/sim/configs/rpproxy/defconfig b/boards/sim/sim/sim/configs/rpproxy/defconfig index 58416401768..7554654060b 100644 --- a/boards/sim/sim/sim/configs/rpproxy/defconfig +++ b/boards/sim/sim/sim/configs/rpproxy/defconfig @@ -16,9 +16,12 @@ CONFIG_BUILTIN=y CONFIG_DEBUG_ASSERTIONS=y CONFIG_DEBUG_ERROR=y CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ERROR=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_RPMSG=y CONFIG_DEV_SIMPLE_ADDRENV=y +CONFIG_EXAMPLES_HELLO=y CONFIG_EXAMPLES_RPMSGSOCKET=y CONFIG_FS_PROCFS=y CONFIG_FS_RPMSGFS=y @@ -26,6 +29,8 @@ CONFIG_IDLETHREAD_STACKSIZE=4096 CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INPUT=y CONFIG_LIBC_HOSTNAME="proxy" +CONFIG_MTD=y +CONFIG_MTD_BYTE_WRITE=y CONFIG_NDEBUG=y CONFIG_NET=y CONFIG_NETDB_DNSCLIENT=y @@ -48,6 +53,7 @@ CONFIG_NSH_READLINE=y CONFIG_OPENAMP=y CONFIG_READLINE_CMD_HISTORY=y CONFIG_READLINE_TABCOMPLETION=y +CONFIG_RPMSGMTD=y CONFIG_RPMSG_UART=y CONFIG_RPTUN=y CONFIG_RTC=y diff --git a/boards/sim/sim/sim/configs/rpserver/defconfig b/boards/sim/sim/sim/configs/rpserver/defconfig index e46e2f517e5..966f059c461 100644 --- a/boards/sim/sim/sim/configs/rpserver/defconfig +++ b/boards/sim/sim/sim/configs/rpserver/defconfig @@ -17,6 +17,8 @@ CONFIG_CLK_RPMSG=y CONFIG_DEBUG_ASSERTIONS=y CONFIG_DEBUG_ERROR=y CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ERROR=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEV_RPMSG_SERVER=y CONFIG_DEV_SIMPLE_ADDRENV=y @@ -30,6 +32,8 @@ CONFIG_INPUT=y CONFIG_IOEXPANDER=y CONFIG_IOEXPANDER_RPMSG=y CONFIG_LIBC_HOSTNAME="server" +CONFIG_MTD=y +CONFIG_MTD_BYTE_WRITE=y CONFIG_NDEBUG=y CONFIG_NET=y CONFIG_NETDB_DNSCLIENT=y @@ -60,10 +64,12 @@ CONFIG_NSH_BUILTIN_APPS=y CONFIG_NSH_PROMPT_STRING="server> " CONFIG_NSH_READLINE=y CONFIG_OPENAMP=y +CONFIG_RAMMTD=y CONFIG_READLINE_CMD_HISTORY=y CONFIG_READLINE_TABCOMPLETION=y CONFIG_REGULATOR=y CONFIG_REGULATOR_RPMSG=y +CONFIG_RPMSGMTD_SERVER=y CONFIG_RPMSG_UART=y CONFIG_RPTUN=y CONFIG_RTC=y diff --git a/boards/sim/sim/sim/src/sim_bringup.c b/boards/sim/sim/sim/src/sim_bringup.c index 11f8eba4eff..bc37dc57cd7 100644 --- a/boards/sim/sim/sim/src/sim_bringup.c +++ b/boards/sim/sim/sim/src/sim_bringup.c @@ -176,14 +176,6 @@ int sim_bringup(void) syslog(LOG_ERR, "ERROR: IOCTL MTDIOC_BULKERASE failed\n"); } -#if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS) - /* Initialize a SMART Flash block device and bind it to the MTD - * device. - */ - - smart_initialize(0, mtd, NULL); - -#elif defined(CONFIG_FS_SPIFFS) /* Register the MTD driver so that it can be accessed from the * VFS. */ @@ -195,6 +187,14 @@ int sim_bringup(void) ret); } +#if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS) + /* Initialize a SMART Flash block device and bind it to the MTD + * device. + */ + + smart_initialize(0, mtd, NULL); + +#elif defined(CONFIG_FS_SPIFFS) /* Mount the SPIFFS file system */ ret = nx_mount("/dev/rammtd", "/mnt/spiffs", "spiffs", 0, NULL); @@ -206,17 +206,6 @@ int sim_bringup(void) } #elif defined(CONFIG_FS_LITTLEFS) - /* Register the MTD driver so that it can be accessed from the - * VFS. - */ - - ret = register_mtddriver("/dev/rammtd", mtd, 0755, NULL); - if (ret < 0) - { - syslog(LOG_ERR, "ERROR: Failed to register MTD driver: %d\n", - ret); - } - /* Mount the LittleFS file system */ ret = nx_mount("/dev/rammtd", "/mnt/lfs", "littlefs", 0, @@ -452,6 +441,10 @@ int sim_bringup(void) rpmsgdev_register("server", "/dev/console", "/dev/server-console"); rpmsgdev_register("server", "/dev/null", "/dev/server-null"); #endif + +#ifdef CONFIG_RPMSGMTD + rpmsgmtd_register("server", "/dev/rammtd", NULL); +#endif #endif #ifdef CONFIG_SIM_WTGAHRS2_UARTN diff --git a/drivers/drivers_initialize.c b/drivers/drivers_initialize.c index 605f35a1a45..085c50a4353 100644 --- a/drivers/drivers_initialize.c +++ b/drivers/drivers_initialize.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -167,4 +168,8 @@ void drivers_initialize(void) #ifdef CONFIG_DEV_RPMSG_SERVER rpmsgdev_server_init(); #endif + +#ifdef CONFIG_RPMSGMTD_SERVER + rpmsgmtd_server_init(); +#endif } diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 08486d94464..3b2ddb4016e 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -137,7 +137,7 @@ config MTD_PROGMEM interfaces must be exported by chip-specific logic. if MTD_PROGMEM - + endif #MTD_PROGMEM config MTD_CONFIG @@ -271,6 +271,16 @@ config MTD_NAND_EMBEDDEDECC endif # MTD_NAND +config RPMSGMTD + bool "MTD RPMSG Client Enable" + default n + depends on RPTUN + +config RPMSGMTD_SERVER + bool "MTD RPMSG Server Enable" + default n + depends on RPTUN + config RAMMTD bool "RAM-based MTD driver" default n @@ -719,11 +729,11 @@ config MX25RXX_SECTOR512 config MX25RXX_PAGE128 bool "128 byte size pages" default n - + config MX25RXX_LXX bool "Run MX25RXX driver in MX25LXX mode" default n - + endif # MTD_MX25RXX config MTD_SMART diff --git a/drivers/mtd/Make.defs b/drivers/mtd/Make.defs index 893d8d50350..461c0c6a80c 100644 --- a/drivers/mtd/Make.defs +++ b/drivers/mtd/Make.defs @@ -68,6 +68,14 @@ ifeq ($(CONFIG_NULLMTD),y) CSRCS += nullmtd.c endif +ifeq ($(CONFIG_RPMSGMTD),y) +CSRCS += rpmsgmtd.c +endif + +ifeq ($(CONFIG_RPMSGMTD_SERVER),y) +CSRCS += rpmsgmtd_server.c +endif + ifeq ($(CONFIG_MTD_AT24XX),y) CSRCS += at24xx.c endif diff --git a/drivers/mtd/rpmsgmtd.c b/drivers/mtd/rpmsgmtd.c new file mode 100644 index 00000000000..6873ece02be --- /dev/null +++ b/drivers/mtd/rpmsgmtd.c @@ -0,0 +1,1118 @@ +/**************************************************************************** + * drivers/mtd/rpmsgmtd.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 "rpmsgmtd.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rpmsgmtd_s +{ + struct mtd_dev_s mtd; /* MTD device */ + 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 geoexcl; /* Get mtd geometry operation mutex */ + struct mtd_geometry_s geo; /* MTD geomerty */ +}; + +/* Rpmsg device cookie used to handle the response from the remote cpu */ + +struct rpmsgmtd_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 mtd operation functions */ + +static int rpmsgmtd_erase(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks); +static int rpmsgmtd_get_geometry(FAR struct rpmsgmtd_s *dev); +static ssize_t rpmsgmtd_bread(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR uint8_t *buffer); +static ssize_t rpmsgmtd_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR const uint8_t *buffer); +static ssize_t rpmsgmtd_read(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR uint8_t *buffer); +#ifdef CONFIG_MTD_BYTE_WRITE +static ssize_t rpmsgmtd_write(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR const uint8_t *buffer); +#endif +static size_t rpmsgmtd_ioctl_arglen(int cmd); +static int rpmsgmtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, + unsigned long arg); + +/* Functions for sending data to the remote cpu */ + +static int rpmsgmtd_send_recv(FAR struct rpmsgmtd_s *priv, + uint32_t command, bool copy, + FAR struct rpmsgmtd_header_s *msg, + int len, FAR void *data); +static FAR void *rpmsgmtd_get_tx_payload_buffer(FAR struct rpmsgmtd_s *priv, + FAR uint32_t *len); + +/* Functions handle the responses from the remote cpu */ + +static int rpmsgmtd_default_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgmtd_bread_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgmtd_read_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgmtd_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 rpmsgmtd_device_created(struct rpmsg_device *rdev, + FAR void *priv_); +static void rpmsgmtd_device_destroy(struct rpmsg_device *rdev, + FAR void *priv_); +static int rpmsgmtd_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv); +static void rpmsgmtd_ns_bound(struct rpmsg_endpoint *ept); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Rpmsg device response handler table */ + +static const rpmsg_ept_cb g_rpmsgmtd_handler[] = +{ + [RPMSGMTD_ERASE] = rpmsgmtd_default_handler, + [RPMSGMTD_BREAD] = rpmsgmtd_bread_handler, + [RPMSGMTD_BWRITE] = rpmsgmtd_default_handler, + [RPMSGMTD_READ] = rpmsgmtd_read_handler, + [RPMSGMTD_WRITE] = rpmsgmtd_default_handler, + [RPMSGMTD_IOCTL] = rpmsgmtd_ioctl_handler, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rpmsgmtd_erase + * + * Description: + * Rpmsg-mtd erase operation + * + * Parameters: + * dev - the mtd device + * startblock - erase start block + * nblocks - erase block number + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int rpmsgmtd_erase(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks) +{ + FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev; + struct rpmsgmtd_erase_s msg; + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + msg.startblock = startblock; + msg.nblocks = nblocks; + + return rpmsgmtd_send_recv(priv, RPMSGMTD_ERASE, true, &msg.header, + sizeof(msg), NULL); +} + +/**************************************************************************** + * Name: rpmsgmtd_get_geometry + * + * Description: + * Rpmsg-mtd get the server mtd device geometry + * + * Parameters: + * dev - the mtd device + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int rpmsgmtd_get_geometry(FAR struct rpmsgmtd_s *dev) +{ + int ret; + + ret = nxmutex_lock(&dev->geoexcl); + if (ret < 0) + { + return ret; + } + + if (dev->geo.blocksize == 0) + { + /* Get the server mtd device geometry */ + + ret = rpmsgmtd_ioctl(&dev->mtd, MTDIOC_GEOMETRY, + (unsigned long)&dev->geo); + } + + nxmutex_unlock(&dev->geoexcl); + return ret; +} + +/**************************************************************************** + * Name: rpmsgmtd_bread + * + * Description: + * Rpmsg-mtd block read operation + * + * Parameters: + * dev - the mtd device + * startblock - read start block + * nblocks - read block number + * buffer - read buffer + * + * Returned Values: + * The positive non-zero number of blocks read on success, 0 on if an + * end-of-file condition, or a negated errno value on any failure. + * + ****************************************************************************/ + +static ssize_t rpmsgmtd_bread(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR uint8_t *buffer) +{ + FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev; + struct rpmsgmtd_bread_s msg; + struct iovec iov; + int ret; + + if (buffer == NULL) + { + return -EINVAL; + } + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + /* Get the server mtd geometry */ + + ret = rpmsgmtd_get_geometry(priv); + 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.startblock = startblock; + msg.nblocks = nblocks; + msg.blocksize = priv->geo.blocksize; + + ret = rpmsgmtd_send_recv(priv, RPMSGMTD_BREAD, true, &msg.header, + sizeof(msg) - 1, &iov); + + return ret < 0 ? ret : iov.iov_len; +} + +/**************************************************************************** + * Name: rpmsgmtd_bwrite + * + * Description: + * Rpmsg-mtd block write operation + * + * Parameters: + * dev - the mtd device + * startblock - write start block + * nblocks - write block number + * buffer - write buffer + * + * Returned Values: + * On success, the number of blocks 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 rpmsgmtd_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR const uint8_t *buffer) +{ + FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev; + FAR struct rpmsgmtd_bwrite_s *msg; + struct rpmsgmtd_cookie_s cookie; + uint32_t blocksize; + uint32_t space; + size_t written = 0; + int ret; + + if (buffer == NULL) + { + return -EINVAL; + } + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + /* Get the server mtd geometry */ + + ret = rpmsgmtd_get_geometry(priv); + 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); + nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE); + + blocksize = priv->geo.blocksize; + while (written < nblocks) + { + msg = rpmsgmtd_get_tx_payload_buffer(priv, &space); + if (msg == NULL) + { + ret = -ENOMEM; + goto out; + } + + DEBUGASSERT(sizeof(*msg) - 1 + blocksize <= space); + + msg->nblocks = (space - sizeof(*msg) + 1) / blocksize; + if (msg->nblocks >= nblocks - written) + { + /* Send complete, set cookie is valid, need ack */ + + msg->nblocks = nblocks - 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 = RPMSGMTD_BWRITE; + msg->header.result = -ENXIO; + msg->startblock = startblock; + msg->blocksize = blocksize; + memcpy(msg->buf, buffer, msg->nblocks * blocksize); + + buffer += msg->nblocks * blocksize; + startblock += msg->nblocks; + written += msg->nblocks; + + ret = rpmsg_send_nocopy(&priv->ept, msg, + sizeof(*msg) - 1 + msg->nblocks * blocksize); + 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 : nblocks; +} + +/**************************************************************************** + * Name: rpmsgmtd_read + * + * Description: + * Rpmsg-mtd read operation + * + * Parameters: + * dev - the mtd device + * offset - read offset address in the mtd 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 rpmsgmtd_read(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR uint8_t *buffer) +{ + FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev; + struct rpmsgmtd_read_s msg; + struct iovec iov; + ssize_t ret; + + if (buffer == NULL) + { + return -EINVAL; + } + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + /* Call the host to perform the read */ + + iov.iov_base = buffer; + iov.iov_len = 0; + + msg.offset = offset; + msg.nbytes = nbytes; + + ret = rpmsgmtd_send_recv(priv, RPMSGMTD_READ, true, &msg.header, + sizeof(msg) - 1, &iov); + + return ret < 0 ? ret : iov.iov_len; +} + +/**************************************************************************** + * Name: rpmsgmtd_write + * + * Description: + * Rpmsg-mtd write operation + * + * Parameters: + * dev - the mtd device + * offset - write offset address in the mtd 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). + * + ****************************************************************************/ + +#ifdef CONFIG_MTD_BYTE_WRITE +static ssize_t rpmsgmtd_write(FAR struct mtd_dev_s *dev, off_t offset, + size_t nbytes, FAR const uint8_t *buffer) +{ + FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev; + FAR struct rpmsgmtd_write_s *msg; + struct rpmsgmtd_cookie_s cookie; + uint32_t space; + size_t written = 0; + int ret; + + if (buffer == NULL) + { + return -EINVAL; + } + + /* Sanity checks */ + + DEBUGASSERT(priv != NULL); + + /* Perform the rpmsg write */ + + memset(&cookie, 0, sizeof(cookie)); + nxsem_init(&cookie.sem, 0, 0); + nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE); + + while (written < nbytes) + { + msg = rpmsgmtd_get_tx_payload_buffer(priv, &space); + if (msg == NULL) + { + ret = -ENOMEM; + goto out; + } + + space -= sizeof(*msg) - 1; + if (space >= nbytes - written) + { + /* Send complete, set cookie is valid, need ack */ + + space = nbytes - 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 = RPMSGMTD_WRITE; + msg->header.result = -ENXIO; + msg->offset = offset; + msg->nbytes = space; + memcpy(msg->buf, buffer, space); + + ret = rpmsg_send_nocopy(&priv->ept, msg, sizeof(*msg) - 1 + space); + if (ret < 0) + { + goto out; + } + + buffer += space; + offset += space; + written += space; + } + + ret = rpmsg_wait(&priv->ept, &cookie.sem); + if (ret < 0) + { + goto out; + } + + ret = cookie.result; + +out: + nxsem_destroy(&cookie.sem); + return ret < 0 ? ret : nbytes; +} +#endif + +/**************************************************************************** + * Name: rpmsgmtd_ioctl_arglen + * + * Description: + * Get rpmsg mtd 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 rpmsgmtd_ioctl_arglen(int cmd) +{ + switch (cmd) + { + case MTDIOC_GEOMETRY: + return sizeof(struct mtd_geometry_s); + case MTDIOC_PROTECT: + case MTDIOC_UNPROTECT: + return sizeof(struct mtd_protect_s); + default: + return 0; + } +} + +/**************************************************************************** + * Name: rpmsgmtd_ioctl + * + * Description: + * Rpmsg-mtd ioctl operation + * + * Parameters: + * dev - the mtd device + * cmd - the ioctl command + * arg - the ioctl arguments + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int rpmsgmtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, + unsigned long arg) +{ + FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev; + FAR struct rpmsgmtd_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 = rpmsgmtd_ioctl_arglen(cmd); + msglen = sizeof(*msg) + arglen - 1; + + msg = rpmsgmtd_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 rpmsgmtd_send_recv(priv, RPMSGMTD_IOCTL, false, &msg->header, + msglen, arglen > 0 ? (FAR void *)arg : NULL); +} + +/**************************************************************************** + * Name: rpmsgmtd_get_tx_payload_buffer + * + * Description: + * Get the rpmsg mtd tx payload, the buffer is from the rpmsg share memory + * that can be accessed by local and remote cpu. + * + * Parameters: + * priv - The rpmsg-mtd handle + * len - The got memroy size + * + * Returned Values: + * NULL - failure + * not NULL - success + * + ****************************************************************************/ + +static FAR void *rpmsgmtd_get_tx_payload_buffer(FAR struct rpmsgmtd_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: rpmsgmtd_send_recv + * + * Description: + * Send and receive the rpmsg data. + * + * Parameters: + * priv - rpmsg mtd handle + * command - the command, RPMSGMTD_OPEN, RPMSGMTD_CLOSE, RPMSGMTD_READ, + * RPMSGMTD_WRITE, RPMSGMTD_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 rpmsgmtd_send_recv(FAR struct rpmsgmtd_s *priv, + uint32_t command, bool copy, + FAR struct rpmsgmtd_header_s *msg, + int len, FAR void *data) +{ + struct rpmsgmtd_cookie_s cookie; + int ret; + + memset(&cookie, 0, sizeof(cookie)); + nxsem_init(&cookie.sem, 0, 0); + nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE); + + 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: rpmsgmtd_default_handler + * + * Description: + * Default rpmsg-mtd response handler, this function will be called to + * process the return message of rpmsgmtd_open(), rpmsgmtd_close() and + * rpmsgmtd_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 rpmsgmtd_default_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_header_s *header = data; + FAR struct rpmsgmtd_cookie_s *cookie = + (FAR struct rpmsgmtd_cookie_s *)(uintptr_t)header->cookie; + + cookie->result = header->result; + if (cookie->result >= 0 && cookie->data) + { + memcpy(cookie->data, data, len); + } + + rpmsg_post(ept, &cookie->sem); + return 0; +} + +/**************************************************************************** + * Name: rpmsgmtd_bread_handler + * + * Description: + * Rpmsg-mtd block read response handler, this function will be called to + * process the return message of rpmsgmtd_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 rpmsgmtd_bread_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_header_s *header = data; + FAR struct rpmsgmtd_cookie_s *cookie = + (FAR struct rpmsgmtd_cookie_s *)(uintptr_t)header->cookie; + FAR struct rpmsgmtd_bread_s *rsp = data; + FAR struct iovec *iov = cookie->data; + size_t read; + + cookie->result = header->result; + if (cookie->result > 0) + { + read = cookie->result * rsp->blocksize; + memcpy(iov->iov_base, rsp->buf, read); + iov->iov_base += read; + iov->iov_len += cookie->result; + } + + if (cookie->result <= 0 || iov->iov_len >= rsp->nblocks) + { + rpmsg_post(ept, &cookie->sem); + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgmtd_read_handler + * + * Description: + * Rpmsg-mtd read response handler, this function will be called to + * process the return message of rpmsgmtd_read(). + * + * Parameters: + * ept - The rpmsg endpoint + * data - The return message + * len - The return message length + * src - unknow + * priv - unknow + * + * Returned Values: + * Always OK + * + ****************************************************************************/ + +static int rpmsgmtd_read_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_header_s *header = data; + FAR struct rpmsgmtd_cookie_s *cookie = + (FAR struct rpmsgmtd_cookie_s *)(uintptr_t)header->cookie; + FAR struct rpmsgmtd_read_s *rsp = data; + FAR struct iovec *iov = cookie->data; + + cookie->result = header->result; + if (cookie->result > 0) + { + memcpy(iov->iov_base + iov->iov_len, rsp->buf, cookie->result); + iov->iov_len += cookie->result; + } + + if (cookie->result <= 0 || iov->iov_len >= rsp->nbytes) + { + rpmsg_post(ept, &cookie->sem); + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgmtd_ioctl_handler + * + * Description: + * Rpmsg-mtd ioctl response handler, this function will be called to + * process the return message of rpmsgmtd_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 rpmsgmtd_ioctl_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_header_s *header = data; + FAR struct rpmsgmtd_cookie_s *cookie = + (FAR struct rpmsgmtd_cookie_s *)(uintptr_t)header->cookie; + FAR struct rpmsgmtd_ioctl_s *rsp = data; + + if (cookie->result >= 0 && rsp->arglen > 0) + { + memcpy(cookie->data, (FAR void *)(uintptr_t)rsp->buf, rsp->arglen); + } + + rpmsg_post(ept, &cookie->sem); + return 0; +} + +/**************************************************************************** + * Name: rpmsgmtd_ns_bound + * + * Description: + * Rpmsg mtd end point service bound callback function , called when + * remote end point address is received. + * + * Parameters: + * ept - The rpmsg-mtd end point + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void rpmsgmtd_ns_bound(FAR struct rpmsg_endpoint *ept) +{ + FAR struct rpmsgmtd_s *priv = ept->priv; + + rpmsg_post(&priv->ept, &priv->wait); +} + +/**************************************************************************** + * Name: rpmsgmtd_device_created + * + * Description: + * Rpmsg mtd create function, this function will be called by rptun to + * create a rpmsg-mtd end point. + * + * Parameters: + * rdev - The rpmsg-mtd end point + * priv_ - Rpmsg-mtd handle + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void rpmsgmtd_device_created(FAR struct rpmsg_device *rdev, + FAR void *priv_) +{ + FAR struct rpmsgmtd_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 = rpmsgmtd_ns_bound; + snprintf(buf, sizeof(buf), "%s%s", RPMSGMTD_NAME_PREFIX, + priv->remotepath); + rpmsg_create_ept(&priv->ept, rdev, buf, + RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, + rpmsgmtd_ept_cb, NULL); + } +} + +/**************************************************************************** + * Name: rpmsgmtd_device_destroy + * + * Description: + * Rpmsg mtd destroy function, this function will be called by rptun to + * destroy rpmsg-mtd end point. + * + * Parameters: + * rdev - The rpmsg-mtd end point + * priv_ - Rpmsg-mtd handle + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void rpmsgmtd_device_destroy(FAR struct rpmsg_device *rdev, + FAR void *priv_) +{ + FAR struct rpmsgmtd_s *priv = priv_; + + if (strcmp(priv->remotecpu, rpmsg_get_cpuname(rdev)) == 0) + { + rpmsg_destroy_ept(&priv->ept); + } +} + +/**************************************************************************** + * Name: rpmsgmtd_ept_cb + * + * Description: + * Rpmsg mtd end point callback function, this function will be called + * when receive the remote cpu message. + * + * Parameters: + * ept - The rpmsg-mtd 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 rpmsgmtd_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv) +{ + FAR struct rpmsgmtd_header_s *header = data; + uint32_t command = header->command; + + if (command < ARRAY_SIZE(g_rpmsgmtd_handler)) + { + return g_rpmsgmtd_handler[command](ept, data, len, src, priv); + } + + return -EINVAL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rpmsgmtd_register + * + * Description: + * Rpmsg-mtd 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 rpmsgmtd_register(FAR const char *remotecpu, FAR const char *remotepath, + FAR const char *localpath) +{ + FAR struct rpmsgmtd_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->mtd.erase = rpmsgmtd_erase; + dev->mtd.bread = rpmsgmtd_bread; + dev->mtd.bwrite = rpmsgmtd_bwrite; + dev->mtd.read = rpmsgmtd_read; +#ifdef CONFIG_MTD_BYTE_WRITE + dev->mtd.write = rpmsgmtd_write; +#endif + dev->mtd.ioctl = rpmsgmtd_ioctl; + dev->mtd.name = "rpmsgmtd"; + + /* Initialize the rpmsg device */ + + dev->remotecpu = remotecpu; + dev->remotepath = remotepath; + + nxsem_init(&dev->wait, 0, 0); + nxsem_set_protocol(&dev->wait, SEM_PRIO_NONE); + nxmutex_init(&dev->geoexcl); + + /* Register the rpmsg callback */ + + ret = rpmsg_register_callback(dev, + rpmsgmtd_device_created, + rpmsgmtd_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_mtddriver(localpath, &dev->mtd, 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, + rpmsgmtd_device_created, + rpmsgmtd_device_destroy, + NULL, + NULL); + +fail: + nxsem_destroy(&dev->wait); + kmm_free(dev); + return ret; +} diff --git a/drivers/mtd/rpmsgmtd.h b/drivers/mtd/rpmsgmtd.h new file mode 100644 index 00000000000..523c5159576 --- /dev/null +++ b/drivers/mtd/rpmsgmtd.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * drivers/mtd/rpmsgmtd.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_MTD_RPMSGMTD_H +#define __DRIVERS_MTD_RPMSGMTD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#define RPMSGMTD_NAME_PREFIX "rpmsgmtd-" +#define RPMSGMTD_NAME_PREFIX_LEN 9 + +#define RPMSGMTD_ERASE 1 +#define RPMSGMTD_BREAD 2 +#define RPMSGMTD_BWRITE 3 +#define RPMSGMTD_READ 4 +#define RPMSGMTD_WRITE 5 +#define RPMSGMTD_IOCTL 6 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +begin_packed_struct struct rpmsgmtd_header_s +{ + uint32_t command; + int32_t result; + uint64_t cookie; +} end_packed_struct; + +begin_packed_struct struct rpmsgmtd_erase_s +{ + struct rpmsgmtd_header_s header; + int64_t startblock; + uint64_t nblocks; +} end_packed_struct; + +begin_packed_struct struct rpmsgmtd_bread_s +{ + struct rpmsgmtd_header_s header; + int64_t startblock; + uint64_t nblocks; + uint32_t blocksize; + uint8_t buf[1]; +} end_packed_struct; + +#define rpmsgmtd_bwrite_s rpmsgmtd_bread_s + +begin_packed_struct struct rpmsgmtd_read_s +{ + struct rpmsgmtd_header_s header; + int64_t offset; + uint64_t nbytes; + uint8_t buf[1]; +} end_packed_struct; + +#define rpmsgmtd_write_s rpmsgmtd_read_s + +begin_packed_struct struct rpmsgmtd_ioctl_s +{ + struct rpmsgmtd_header_s header; + int32_t request; + uint64_t arg; + uint32_t arglen; + uint8_t buf[1]; +} end_packed_struct; + +/**************************************************************************** + * Internal function prototypes + ****************************************************************************/ + +/**************************************************************************** + * Internal data + ****************************************************************************/ + +#endif /* __DRIVERS_MTD_RPMSGMTD_H */ diff --git a/drivers/mtd/rpmsgmtd_server.c b/drivers/mtd/rpmsgmtd_server.c new file mode 100644 index 00000000000..fd6377866f5 --- /dev/null +++ b/drivers/mtd/rpmsgmtd_server.c @@ -0,0 +1,420 @@ +/**************************************************************************** + * drivers/mtd/rpmsgmtd_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 +#include + +#include "rpmsgmtd.h" + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rpmsgmtd_server_s +{ + struct rpmsg_endpoint ept; + FAR struct mtd_dev_s *dev; + FAR struct inode *mtdnode; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Functions handle the messages from the client cpu */ + +static int rpmsgmtd_erase_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgmtd_bread_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgmtd_bwrite_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgmtd_read_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgmtd_write_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int rpmsgmtd_ioctl_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 rpmsgmtd_ns_match(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest); +static void rpmsgmtd_ns_bind(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest); +static void rpmsgmtd_ns_unbind(FAR struct rpmsg_endpoint *ept); +static int rpmsgmtd_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_rpmsgmtd_handler[] = +{ + [RPMSGMTD_ERASE] = rpmsgmtd_erase_handler, + [RPMSGMTD_BREAD] = rpmsgmtd_bread_handler, + [RPMSGMTD_BWRITE] = rpmsgmtd_bwrite_handler, + [RPMSGMTD_READ] = rpmsgmtd_read_handler, + [RPMSGMTD_WRITE] = rpmsgmtd_write_handler, + [RPMSGMTD_IOCTL] = rpmsgmtd_ioctl_handler, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rpmsgmtd_erase_handler + ****************************************************************************/ + +static int rpmsgmtd_erase_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_server_s *server = ept->priv; + FAR struct rpmsgmtd_erase_s *msg = data; + + msg->header.result = MTD_ERASE(server->dev, msg->startblock, msg->nblocks); + + return rpmsg_send(ept, msg, sizeof(*msg)); +} + +/**************************************************************************** + * Name: rpmsgmtd_bread_handler + ****************************************************************************/ + +static int rpmsgmtd_bread_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_server_s *server = ept->priv; + FAR struct rpmsgmtd_bread_s *msg = data; + FAR struct rpmsgmtd_bread_s *rsp; + int ret = -ENOENT; + size_t read = 0; + size_t nblocks; + uint32_t space; + + while (read < msg->nblocks) + { + 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->blocksize); + + *rsp = *msg; + + nblocks = (space - sizeof(*msg) + 1) / msg->blocksize; + if (nblocks > msg->nblocks - read) + { + nblocks = msg->nblocks - read; + } + + ret = MTD_BREAD(server->dev, msg->startblock + read, nblocks, + rsp->buf); + + rsp->header.result = ret; + rpmsg_send_nocopy(ept, rsp, (ret < 0 ? 0 : ret * msg->blocksize) + + sizeof(*rsp) - 1); + if (ret <= 0) + { + ferr("mtd block read failed\n"); + break; + } + + read += ret; + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgmtd_bwrite_handler + ****************************************************************************/ + +static int rpmsgmtd_bwrite_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_server_s *server = ept->priv; + FAR struct rpmsgmtd_bwrite_s *msg = data; + int ret; + + ret = MTD_BWRITE(server->dev, msg->startblock, msg->nblocks, msg->buf); + 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; + rpmsg_send(ept, msg, sizeof(*msg) - 1); + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgmtd_read_handler + ****************************************************************************/ + +static int rpmsgmtd_read_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_server_s *server = ept->priv; + FAR struct rpmsgmtd_read_s *msg = data; + FAR struct rpmsgmtd_read_s *rsp; + int ret = -ENOENT; + size_t read = 0; + uint32_t space; + + while (read < msg->nbytes) + { + rsp = rpmsg_get_tx_payload_buffer(ept, &space, true); + if (rsp == NULL) + { + ferr("get tx payload failed\n"); + return -ENOMEM; + } + + *rsp = *msg; + + space -= sizeof(*msg) - 1; + if (space > msg->nbytes - read) + { + space = msg->nbytes - read; + } + + ret = MTD_READ(server->dev, msg->offset + read, space, + (FAR uint8_t *)rsp->buf); + + rsp->header.result = ret; + rpmsg_send_nocopy(ept, rsp, (ret < 0 ? 0 : ret) + sizeof(*rsp) - 1); + if (ret <= 0) + { + break; + } + + read += ret; + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgmtd_write_handler + ****************************************************************************/ + +static int rpmsgmtd_write_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_server_s *server = ept->priv; + FAR struct rpmsgmtd_write_s *msg = data; + int ret; + + ret = MTD_WRITE(server->dev, msg->offset, msg->nbytes, msg->buf); + if (ret <= 0) + { + ferr("mtd write failed\n"); + } + + /* cookie != 0 indicate the data has been sent complete, so send back + * the total written bytes. + */ + + if (msg->header.cookie != 0) + { + msg->header.result = ret; + rpmsg_send(ept, msg, sizeof(*msg) - 1); + } + + return 0; +} + +/**************************************************************************** + * Name: rpmsgmtd_ioctl_handler + ****************************************************************************/ + +static int rpmsgmtd_ioctl_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct rpmsgmtd_server_s *server = ept->priv; + FAR struct rpmsgmtd_ioctl_s *msg = data; + + msg->header.result = MTD_IOCTL(server->dev, msg->request, + msg->arglen > 0 ? (unsigned long)msg->buf : + msg->arg); + + return rpmsg_send(ept, msg, len); +} + +/**************************************************************************** + * Name: rpmsgmtd_ns_match + ****************************************************************************/ + +static bool rpmsgmtd_ns_match(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest) +{ + return !strncmp(name, RPMSGMTD_NAME_PREFIX, RPMSGMTD_NAME_PREFIX_LEN); +} + +/**************************************************************************** + * Name: rpmsgmtd_ns_bind + ****************************************************************************/ + +static void rpmsgmtd_ns_bind(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest) +{ + FAR struct rpmsgmtd_server_s *server; + FAR struct inode *mtdnode; + int ret; + + server = kmm_zalloc(sizeof(*server)); + if (server == NULL) + { + ferr("mtd server malloced failed\n"); + return; + } + + ret = find_mtddriver(&name[RPMSGMTD_NAME_PREFIX_LEN], &mtdnode); + if (ret < 0) + { + ferr("mtd device find failed, ret=%d\n", ret); + goto errout; + } + + server->ept.priv = server; + server->mtdnode = mtdnode; + server->dev = mtdnode->u.i_mtd; + + ret = rpmsg_create_ept(&server->ept, rdev, name, + RPMSG_ADDR_ANY, dest, + rpmsgmtd_ept_cb, rpmsgmtd_ns_unbind); + if (ret < 0) + { + ferr("endpoint create failed, ret=%d\n", ret); + close_mtddriver(mtdnode); + goto errout; + } + + return; + +errout: + kmm_free(server); +} + +/**************************************************************************** + * Name: rpmsgmtd_ns_unbind + ****************************************************************************/ + +static void rpmsgmtd_ns_unbind(FAR struct rpmsg_endpoint *ept) +{ + FAR struct rpmsgmtd_server_s *server = ept->priv; + + rpmsg_destroy_ept(&server->ept); + close_mtddriver(server->mtdnode); + kmm_free(server); +} + +/**************************************************************************** + * Name: rpmsgmtd_ept_cb + ****************************************************************************/ + +static int rpmsgmtd_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv) +{ + FAR struct rpmsgmtd_header_s *header = data; + uint32_t command = header->command; + + if (command < ARRAY_SIZE(g_rpmsgmtd_handler)) + { + return g_rpmsgmtd_handler[command](ept, data, len, src, priv); + } + + return -EINVAL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rpmsgmtd_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 rpmsgmtd_server_init(void) +{ + return rpmsg_register_callback(NULL, + NULL, + NULL, + rpmsgmtd_ns_match, + rpmsgmtd_ns_bind); +} diff --git a/include/nuttx/mtd/mtd.h b/include/nuttx/mtd/mtd.h index 3039bf950a0..a029b9a4b09 100644 --- a/include/nuttx/mtd/mtd.h +++ b/include/nuttx/mtd/mtd.h @@ -687,6 +687,49 @@ bool filemtd_isfilemtd(FAR struct mtd_dev_s *mtd); FAR struct mtd_dev_s *nullmtd_initialize(size_t mtdlen, int16_t sectsize, int32_t erasesize); +/**************************************************************************** + * Name: rpmsgmtd_register + * + * Description: + * Rpmsg-mtd client register 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_RPMSGMTD +int rpmsgmtd_register(FAR const char *remotecpu, FAR const char *remotepath, + FAR const char *localpath); +#endif + +/**************************************************************************** + * Name: rpmsgmtd_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. + * + ****************************************************************************/ + +#ifdef CONFIG_RPMSGMTD_SERVER +int rpmsgmtd_server_init(void); +#endif + #undef EXTERN #ifdef __cplusplus }