* drivers/sensors/sensor_rpmsg.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <fcntl.h>
#include <debug.h>
#include <libgen.h>
#include <nuttx/nuttx.h>
#include <nuttx/list.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mutex.h>
#include <nuttx/rwsem.h>
#include <nuttx/sensors/sensor.h>
#include <nuttx/rpmsg/rpmsg.h>
* Pre-processor Definitions
****************************************************************************/
#define SENSOR_RPMSG_EPT_NAME "rpmsg-sensor"
#define SENSOR_RPMSG_ADVERTISE 0
#define SENSOR_RPMSG_ADVERTISE_ACK 1
#define SENSOR_RPMSG_UNADVERTISE 2
#define SENSOR_RPMSG_SUBSCRIBE 3
#define SENSOR_RPMSG_SUBSCRIBE_ACK 4
#define SENSOR_RPMSG_UNSUBSCRIBE 5
#define SENSOR_RPMSG_PUBLISH 6
#define SENSOR_RPMSG_IOCTL 7
#define SENSOR_RPMSG_IOCTL_ACK 8
#define SENSOR_RPMSG_IOCTL_TIMEOUT 1
#define SENSOR_RPMSG_FUNCTION(name, cmd, arg1, arg2, size, wait, type) \
static int sensor_rpmsg_##name(FAR struct sensor_lowerhalf_s *lower, \
FAR struct file *filep, \
type arg1) \
{ \
FAR struct sensor_rpmsg_dev_s *dev = lower->priv; \
FAR struct sensor_lowerhalf_s *drv = dev->drv; \
int ret; \
\
if (drv->ops->name) \
{ \
return drv->ops->name(drv, filep, arg2); \
} \
else if (!(filep->f_oflags & SENSOR_REMOTE)) \
{ \
ret = sensor_rpmsg_ioctl(dev, cmd, arg1, size, wait); \
return wait ? ret : 0; \
} \
else \
{ \
return wait ? -ENOTSUP : 0; \
} \
} \
* Private Types
****************************************************************************/
struct sensor_rpmsg_dev_s
{
struct sensor_lowerhalf_s lower;
FAR struct sensor_lowerhalf_s *drv;
struct list_node node;
struct list_node stublist;
struct list_node proxylist;
sem_t proxysem;
int16_t nadvertisers;
int16_t nsubscribers;
FAR void *upper;
sensor_push_event_t push_event;
sensor_notify_interval_t notify_interval;
FAR const char *name;
char path[1];
};
struct sensor_rpmsg_ept_s
{
struct list_node node;
struct rpmsg_endpoint ept;
struct work_s work;
struct work_s bound_work;
rmutex_t lock;
FAR void *buffer;
uint64_t expire;
uint32_t space;
size_t written;
};
struct sensor_rpmsg_stub_s
{
struct list_node node;
FAR struct rpmsg_endpoint *ept;
uint64_t cookie;
struct file file;
bool flushing;
bool wakeup;
};
struct sensor_rpmsg_proxy_s
{
struct list_node node;
FAR struct rpmsg_endpoint *ept;
uint64_t cookie;
bool wakeup;
};
* subscription and remote advertisement.
*/
struct sensor_rpmsg_advsub_s
{
uint32_t command;
uint32_t nbuffer;
uint64_t cookie;
uint32_t persist;
char path[1];
};
* include remote receiver, the length of data and the data payload.
* The structure sensor_rpmsg_data_s describes a set of data message.
*/
struct sensor_rpmsg_cell_s
{
uint64_t cookie;
uint32_t nbuffer;
uint32_t len;
char data[0];
};
struct sensor_rpmsg_data_s
{
uint32_t command;
uint32_t reserved;
struct sensor_rpmsg_cell_s cell[0];
};
* it supports pass pointer to remove device by cookie_xx member.
*/
struct sensor_rpmsg_ioctl_cookie_s
{
sem_t sem;
FAR void *data;
int result;
};
struct sensor_rpmsg_ioctl_s
{
uint32_t command;
int32_t result;
uint64_t cookie;
uint64_t proxy;
int32_t request;
uint32_t arglen;
char arg[];
};
* Private Function Prototypes
****************************************************************************/
static int sensor_rpmsg_open(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep);
static int sensor_rpmsg_close(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep);
static int sensor_rpmsg_activate(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
bool enable);
static int sensor_rpmsg_set_interval(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
FAR uint32_t *period_us);
static int sensor_rpmsg_batch(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
FAR uint32_t *latency_us);
static int sensor_rpmsg_flush(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep);
static int sensor_rpmsg_selftest(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
unsigned long arg);
static int sensor_rpmsg_set_calibvalue(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
unsigned long arg);
static int sensor_rpmsg_calibrate(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
unsigned long arg);
static int sensor_rpmsg_get_info(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
FAR struct sensor_device_info_s *info);
static int sensor_rpmsg_set_wakeup(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
bool wakeup);
static int sensor_rpmsg_control(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
int cmd, unsigned long arg);
static int sensor_rpmsg_adv_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
static int sensor_rpmsg_advack_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
static int sensor_rpmsg_unadv_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
static int sensor_rpmsg_sub_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
static int sensor_rpmsg_suback_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
static int sensor_rpmsg_unsub_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
static int sensor_rpmsg_publish_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
static int sensor_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
static int sensor_rpmsg_ioctlack_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv);
* Private Data
****************************************************************************/
static const struct sensor_ops_s g_sensor_rpmsg_ops =
{
.open = sensor_rpmsg_open,
.close = sensor_rpmsg_close,
.activate = sensor_rpmsg_activate,
.set_interval = sensor_rpmsg_set_interval,
.batch = sensor_rpmsg_batch,
.flush = sensor_rpmsg_flush,
.selftest = sensor_rpmsg_selftest,
.set_calibvalue = sensor_rpmsg_set_calibvalue,
.calibrate = sensor_rpmsg_calibrate,
.get_info = sensor_rpmsg_get_info,
.set_wakeup = sensor_rpmsg_set_wakeup,
.control = sensor_rpmsg_control
};
static const rpmsg_ept_cb g_sensor_rpmsg_handler[] =
{
[SENSOR_RPMSG_ADVERTISE] = sensor_rpmsg_adv_handler,
[SENSOR_RPMSG_ADVERTISE_ACK] = sensor_rpmsg_advack_handler,
[SENSOR_RPMSG_UNADVERTISE] = sensor_rpmsg_unadv_handler,
[SENSOR_RPMSG_SUBSCRIBE] = sensor_rpmsg_sub_handler,
[SENSOR_RPMSG_SUBSCRIBE_ACK] = sensor_rpmsg_suback_handler,
[SENSOR_RPMSG_UNSUBSCRIBE] = sensor_rpmsg_unsub_handler,
[SENSOR_RPMSG_PUBLISH] = sensor_rpmsg_publish_handler,
[SENSOR_RPMSG_IOCTL] = sensor_rpmsg_ioctl_handler,
[SENSOR_RPMSG_IOCTL_ACK] = sensor_rpmsg_ioctlack_handler,
};
static struct list_node g_devlist = LIST_INITIAL_VALUE(g_devlist);
static struct list_node g_eptlist = LIST_INITIAL_VALUE(g_eptlist);
static rw_semaphore_t g_ept_lock = RWSEM_INITIALIZER;
static rw_semaphore_t g_dev_lock = RWSEM_INITIALIZER;
* Private Functions
****************************************************************************/
static void sensor_rpmsg_lock(FAR struct sensor_rpmsg_dev_s *dev)
{
dev->lower.sensor_lock(dev->upper);
}
static void sensor_rpmsg_unlock(FAR struct sensor_rpmsg_dev_s *dev)
{
dev->lower.sensor_unlock(dev->upper);
}
static void sensor_rpmsg_advsub_one(FAR struct sensor_rpmsg_dev_s *dev,
FAR struct rpmsg_endpoint *ept,
int command)
{
FAR struct sensor_rpmsg_advsub_s *msg;
uint32_t space;
int len = strlen(dev->path) + 1;
int ret;
msg = rpmsg_get_tx_payload_buffer(ept, &space, true);
if (!msg)
{
snerr("ERROR: advsub:%d get buffer failed:%s, %s\n",
command, dev->path, rpmsg_get_cpuname(ept->rdev));
return;
}
msg->command = command;
msg->cookie = (uint64_t)(uintptr_t)dev;
msg->nbuffer = dev->lower.nbuffer;
msg->persist = dev->lower.persist;
memcpy(msg->path, dev->path, len);
ret = rpmsg_send_nocopy(ept, msg, sizeof(*msg) + len);
if (ret < 0)
{
rpmsg_release_tx_buffer(ept, msg);
snerr("ERROR: advsub:%d rpmsg send failed:%s, %d, %s\n",
command, dev->path, ret, rpmsg_get_cpuname(ept->rdev));
}
}
static void sensor_rpmsg_advsub(FAR struct sensor_rpmsg_dev_s *dev,
int command)
{
FAR struct sensor_rpmsg_ept_s *sre;
down_read(&g_ept_lock);
list_for_every_entry(&g_eptlist, sre, struct sensor_rpmsg_ept_s,
node)
{
FAR struct sensor_rpmsg_proxy_s *proxy = NULL;
bool find = false;
bool adv = false;
if (command == SENSOR_RPMSG_SUBSCRIBE ||
command == SENSOR_RPMSG_UNSUBSCRIBE)
{
list_for_every_entry(&dev->proxylist, proxy,
struct sensor_rpmsg_proxy_s, node)
{
if (proxy->ept == &sre->ept)
{
find = true;
break;
}
}
}
else
{
* will be lost if the following two conditions occur at the same
* time.
* 1.The adv core crashed, the advertiser has a long life cycle.
* 2.The remote subscriber has a long life cycle, and the remote
* core side has not been restarted
*/
adv = true;
}
* 1. If the proxy corresponding to the EPT (Endpoint) did not
* exist previously, this constitutes the first broadcast.
* 2. If the proxy previously had a wakeup attribute, it should
* be broadcast every time.
* 3. If the proxy does not have the wakeup attribute and the
* target core is in the running state, we should still broadcast
* it.
*
* In summary, Let's avoid broadcasting non-wakeup sensors when the
* target core is in a sleep state to prevent unnecessary wakeups.
*/
if (adv || rpmsg_is_running(sre->ept.rdev) || (find && proxy->wakeup))
{
sensor_rpmsg_advsub_one(dev, &sre->ept, command);
}
else
{
sninfo("INFO: advsub:%d %s ignore broadcast to %s, "
"as %d, %d, %d\n",
command, dev->path, rpmsg_get_cpuname(sre->ept.rdev),
find, proxy ? proxy->wakeup : 0,
rpmsg_is_running(sre->ept.rdev));
}
}
up_read(&g_ept_lock);
}
static int sensor_rpmsg_ioctl(FAR struct sensor_rpmsg_dev_s *dev,
int cmd, unsigned long arg, size_t len,
bool wait)
{
struct sensor_rpmsg_ioctl_cookie_s cookie;
FAR struct sensor_rpmsg_proxy_s *proxy;
FAR struct sensor_rpmsg_proxy_s *ptmp;
FAR struct sensor_rpmsg_ioctl_s *msg;
FAR struct rpmsg_endpoint *ept;
uint64_t pcookie;
size_t send_len;
uint32_t space;
int ret = -ENOTTY;
bool empty;
* if device doesn't have proxy, need to wait until proxy is created.
*/
sensor_rpmsg_lock(dev);
empty = list_is_empty(&dev->proxylist);
sensor_rpmsg_unlock(dev);
if (wait)
{
if (empty)
{
ret = nxsem_tickwait_uninterruptible(
&dev->proxysem, SEC2TICK(SENSOR_RPMSG_IOCTL_TIMEOUT));
if (ret < 0)
{
snerr("ERROR: wait proxy create failed:%s, cmd:%d\n",
dev->path, cmd);
return ret;
}
nxsem_post(&dev->proxysem);
}
cookie.data = (FAR void *)(uintptr_t)arg;
cookie.result = -ENXIO;
nxsem_init(&cookie.sem, 0, 0);
}
send_len = len > 0 ? len : sizeof(uint64_t);
sensor_rpmsg_lock(dev);
list_for_every_entry_safe(&dev->proxylist, proxy, ptmp,
struct sensor_rpmsg_proxy_s, node)
{
* before. If it has, record it.
*/
if (cmd == SNIOC_SET_WAKEUP)
{
proxy->wakeup = arg;
}
ept = proxy->ept;
pcookie = proxy->cookie;
msg = rpmsg_get_tx_payload_buffer(ept, &space, true);
if (!msg)
{
ret = -ENOMEM;
snerr("ERROR: ioctl get buffer failed:%s, %s\n",
dev->path, rpmsg_get_cpuname(ept->rdev));
break;
}
msg->command = SENSOR_RPMSG_IOCTL;
msg->cookie = wait ? (uint64_t)(uintptr_t)&cookie : 0;
msg->proxy = pcookie;
msg->request = cmd;
msg->arglen = len;
if (len > 0)
{
memcpy(msg->arg, (FAR void *)(uintptr_t)arg, len);
}
else
{
*(FAR uint64_t *)msg->arg = arg;
}
ret = rpmsg_send_nocopy(ept, msg, sizeof(*msg) + send_len);
if (ret < 0)
{
rpmsg_release_tx_buffer(ept, msg);
snerr("ERROR: ioctl rpmsg send failed:%s, %d, %s\n",
dev->path, ret, rpmsg_get_cpuname(ept->rdev));
break;
}
if (!wait)
{
continue;
}
sensor_rpmsg_unlock(dev);
ret = rpmsg_wait(ept, &cookie.sem);
sensor_rpmsg_lock(dev);
if (ret < 0)
{
snerr("ERROR: ioctl rpmsg wait failed:%s, %d, %s\n",
dev->path, ret, rpmsg_get_cpuname(ept->rdev));
break;
}
ret = cookie.result;
if (ret < 0 && ret != -ENOTTY)
{
break;
}
}
sensor_rpmsg_unlock(dev);
if (wait)
{
nxsem_destroy(&cookie.sem);
}
return ret;
}
static FAR struct sensor_rpmsg_proxy_s *
sensor_rpmsg_alloc_proxy(FAR struct sensor_rpmsg_dev_s *dev,
FAR struct rpmsg_endpoint *ept,
FAR struct sensor_rpmsg_advsub_s *msg,
FAR struct sensor_state_s *state)
{
FAR struct sensor_rpmsg_proxy_s *proxy;
struct file file;
int ret;
sensor_rpmsg_lock(dev);
list_for_every_entry(&dev->proxylist, proxy,
struct sensor_rpmsg_proxy_s, node)
{
if (proxy->ept == ept && proxy->cookie == msg->cookie)
{
sensor_rpmsg_unlock(dev);
return proxy;
}
}
sensor_rpmsg_unlock(dev);
proxy = kmm_zalloc(sizeof(*proxy));
if (!proxy)
{
return NULL;
}
proxy->ept = ept;
proxy->cookie = msg->cookie;
ret = file_open(&file, dev->path, SENSOR_REMOTE | O_CLOEXEC);
if (ret < 0)
{
kmm_free(proxy);
return NULL;
}
file_ioctl(&file, SNIOC_SET_BUFFER_NUMBER, msg->nbuffer);
file_ioctl(&file, SNIOC_GET_STATE, state);
file_close(&file);
sensor_rpmsg_lock(dev);
if (msg->persist)
{
dev->drv->persist = true;
dev->lower.persist = true;
}
list_add_tail(&dev->proxylist, &proxy->node);
nxsem_post(&dev->proxysem);
sensor_rpmsg_unlock(dev);
sminfo(dev->name, "create proxy:%p", proxy);
return proxy;
}
static FAR struct sensor_rpmsg_stub_s *
sensor_rpmsg_push_event_persist(FAR struct sensor_rpmsg_dev_s *dev,
FAR struct rpmsg_endpoint *ept,
FAR struct sensor_rpmsg_stub_s *stub,
uint64_t cookie)
{
FAR struct sensor_rpmsg_cell_s *cell;
FAR struct sensor_rpmsg_stub_s *temp;
FAR struct sensor_rpmsg_data_s *msg;
FAR struct sensor_rpmsg_ept_s *sre;
bool find = false;
uint32_t space;
int ret;
sre = container_of(stub->ept, struct sensor_rpmsg_ept_s, ept);
msg = rpmsg_get_tx_payload_buffer(&sre->ept, &space, true);
if (!msg)
{
snerr("ERROR: push event persist get buffer failed:%s\n",
rpmsg_get_cpuname(sre->ept.rdev));
return NULL;
}
* rpmsg involves recursive calls, which may result in the sub_handler
* not completing its execution, the rpmsg recursively switches to
* the unsub_handler and releases the stub.
*/
list_for_every_entry(&dev->stublist, temp,
struct sensor_rpmsg_stub_s, node)
{
if (temp->ept == ept && temp->cookie == cookie)
{
find = true;
break;
}
}
* node exists. there are two possibilities.
* 1.The node exists, and it's still the address originally allocated
* by malloc.
* 2.The node exists, but the address has changed due to reallocation.
* the stub address needs to be updated. Return to the new address
* of the stub
* 3.The node does not exist anymore,return directly.
*/
if (!find)
{
rpmsg_release_tx_buffer(&sre->ept, msg);
return NULL;
}
else if (stub != temp)
{
stub = temp;
snwarn("WARN: push event persist stub changed:%p -> %p\n", stub, temp);
}
msg->command = SENSOR_RPMSG_PUBLISH;
cell = (FAR struct sensor_rpmsg_cell_s *)(msg + 1);
ret = file_read(&stub->file, cell->data, space - sizeof(*msg) -
sizeof(*cell));
if (ret > 0)
{
cell->len = ret;
cell->cookie = stub->cookie;
cell->nbuffer = dev->lower.nbuffer;
rpmsg_send_nocopy(&sre->ept, msg, sizeof(*msg) +
((sizeof(*cell) + ret + 0x7) & ~0x7));
}
else
{
rpmsg_release_tx_buffer(&sre->ept, msg);
}
return stub;
}
static FAR struct sensor_rpmsg_stub_s *
sensor_rpmsg_alloc_stub(FAR struct sensor_rpmsg_dev_s *dev,
FAR struct rpmsg_endpoint *ept,
uint64_t cookie)
{
FAR struct sensor_rpmsg_stub_s *stub;
int ret;
sensor_rpmsg_lock(dev);
list_for_every_entry(&dev->stublist, stub,
struct sensor_rpmsg_stub_s, node)
{
if (stub->ept == ept && stub->cookie == cookie)
{
sensor_rpmsg_unlock(dev);
return stub;
}
}
sensor_rpmsg_unlock(dev);
stub = kmm_zalloc(sizeof(*stub));
if (!stub)
{
return NULL;
}
stub->ept = ept;
stub->cookie = cookie;
ret = file_open(&stub->file, dev->path,
O_RDOK | O_NONBLOCK | O_CLOEXEC | SENSOR_REMOTE);
if (ret < 0)
{
kmm_free(stub);
return NULL;
}
sensor_rpmsg_lock(dev);
list_add_tail(&dev->stublist, &stub->node);
if (dev->lower.persist)
{
stub = sensor_rpmsg_push_event_persist(dev, ept, stub, cookie);
sminfo(dev->name, "push event persist status:%p", stub);
}
sensor_rpmsg_unlock(dev);
sminfo(dev->name, "create stub:%p", stub);
return stub;
}
static void sensor_rpmsg_free_proxy(FAR struct sensor_rpmsg_dev_s *dev,
FAR struct sensor_rpmsg_proxy_s *proxy)
{
sminfo(dev->name, "free proxy:%p name:%s", proxy, proxy->ept->name);
list_delete(&proxy->node);
kmm_free(proxy);
if (list_is_empty(&dev->proxylist))
{
nxsem_reset(&dev->proxysem, 0);
}
}
static void sensor_rpmsg_free_stub(FAR struct sensor_rpmsg_stub_s *stub)
{
list_delete(&stub->node);
file_close(&stub->file);
kmm_free(stub);
}
static int sensor_rpmsg_open(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep)
{
FAR struct sensor_rpmsg_dev_s *dev = lower->priv;
FAR struct sensor_lowerhalf_s *drv = dev->drv;
bool adv = false;
bool sub = false;
int ret;
if (drv->ops->open)
{
ret = drv->ops->open(drv, filep);
if (ret < 0)
{
return ret;
}
}
if (filep->f_oflags & SENSOR_REMOTE)
{
return 0;
}
sensor_rpmsg_lock(dev);
if (filep->f_oflags & O_WROK)
{
if (filep->f_oflags & SENSOR_PERSIST)
{
dev->lower.persist = true;
}
if (dev->nadvertisers++ <= 0)
{
dev->nadvertisers = 1;
adv = true;
}
}
if (filep->f_oflags & O_RDOK)
{
* physical sensor to avoid waking up remote core.
*/
if (dev->nsubscribers++ == 0 &&
drv->ops->activate == NULL)
{
sub = true;
}
}
sensor_rpmsg_unlock(dev);
if (adv)
{
sensor_rpmsg_advsub(dev, SENSOR_RPMSG_ADVERTISE);
}
if (sub)
{
sensor_rpmsg_advsub(dev, SENSOR_RPMSG_SUBSCRIBE);
}
return 0;
}
static int sensor_rpmsg_close(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep)
{
FAR struct sensor_rpmsg_dev_s *dev = lower->priv;
FAR struct sensor_lowerhalf_s *drv = dev->drv;
FAR struct sensor_rpmsg_stub_s *stub;
FAR struct sensor_rpmsg_stub_s *stmp;
bool unsub = false;
int ret = 0;
if (drv->ops->close)
{
ret = drv->ops->close(drv, filep);
}
if (filep->f_oflags & SENSOR_REMOTE)
{
return ret;
}
sensor_rpmsg_lock(dev);
if (filep->f_oflags & O_WROK)
{
if (dev->nadvertisers == 1)
{
list_for_every_entry_safe(&dev->stublist, stub, stmp,
struct sensor_rpmsg_stub_s, node)
{
sensor_rpmsg_free_stub(stub);
}
}
dev->nadvertisers--;
}
if (filep->f_oflags & O_RDOK)
{
* physical sensor to avoid waking up remote core.
*/
if (dev->nsubscribers == 1 &&
drv->ops->activate == NULL)
{
unsub = true;
}
dev->nsubscribers--;
}
sensor_rpmsg_unlock(dev);
if (unsub)
{
sensor_rpmsg_advsub(dev, SENSOR_RPMSG_UNSUBSCRIBE);
}
return ret;
}
static int sensor_rpmsg_activate(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
bool enable)
{
FAR struct sensor_rpmsg_dev_s *dev = lower->priv;
FAR struct sensor_lowerhalf_s *drv = dev->drv;
if (drv->ops->activate)
{
return drv->ops->activate(drv, filep, enable);
}
return 0;
}
SENSOR_RPMSG_FUNCTION(set_interval, SNIOC_SET_INTERVAL,
*interval, interval, 0, false, uint32_t)
SENSOR_RPMSG_FUNCTION(batch, SNIOC_BATCH, *latency, latency, 0,
false, uint32_t)
SENSOR_RPMSG_FUNCTION(selftest, SNIOC_SELFTEST, arg, arg, 0,
true, unsigned long)
SENSOR_RPMSG_FUNCTION(set_calibvalue, SNIOC_SET_CALIBVALUE,
arg, arg, 256, true, unsigned long)
SENSOR_RPMSG_FUNCTION(calibrate, SNIOC_CALIBRATE, arg, arg, 256,
true, unsigned long)
static int sensor_rpmsg_flush(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep)
{
FAR struct sensor_rpmsg_dev_s *dev = lower->priv;
FAR struct sensor_lowerhalf_s *drv = dev->drv;
int ret = -ENOTTY;
if (drv->ops->flush)
{
ret = drv->ops->flush(drv, filep);
}
else if ((filep->f_oflags & SENSOR_REMOTE) ||
dev->nadvertisers > 0)
{
* and the caller is a remote invocation or the current device
* is an advertiser, then you can still consider the flush
* operation as unsupported and therefore return ENOTSUP
*/
return -ENOTSUP;
}
else
{
sminfo(dev->name, "rpmsg flushing");
ret = sensor_rpmsg_ioctl(dev, SNIOC_FLUSH, 0, 0, true);
sminfo(dev->name, "rpmsg flush send done, ret:%d", ret);
}
return ret;
}
static int sensor_rpmsg_set_wakeup(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
bool wakeup)
{
FAR struct sensor_rpmsg_dev_s *dev = lower->priv;
FAR struct sensor_lowerhalf_s *drv = dev->drv;
int ret = -ENOTTY;
sminfo(dev->name, "rpsmg set wakeup status:%d", wakeup);
if (drv->ops->set_wakeup)
{
ret = drv->ops->set_wakeup(drv, filep, wakeup);
}
else if ((filep->f_oflags & SENSOR_REMOTE) ||
dev->nadvertisers > 0)
{
* and the caller is a remote invocation or the current device
* is an advertiser, then you can still consider the wakeup
* operation as unsupported and therefore return ENOTSUP
*/
return -ENOTSUP;
}
else
{
sminfo(dev->name, "rpsmg set wakeup to remote core:%d", wakeup);
ret = sensor_rpmsg_ioctl(dev, SNIOC_SET_WAKEUP,
wakeup, 0, true);
}
return ret;
}
static int sensor_rpmsg_get_info(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
FAR struct sensor_device_info_s *info)
{
FAR struct sensor_rpmsg_dev_s *dev = lower->priv;
FAR struct sensor_lowerhalf_s *drv = dev->drv;
int ret = -ENOTTY;
if (drv->ops->get_info)
{
ret = drv->ops->get_info(drv, filep, info);
}
if (ret == -ENOTTY && !(filep->f_oflags & SENSOR_REMOTE))
{
ret = sensor_rpmsg_ioctl(dev, SNIOC_GET_INFO,
(unsigned long)(uintptr_t)info,
sizeof(struct sensor_device_info_s), true);
}
return ret;
}
static int sensor_rpmsg_control(FAR struct sensor_lowerhalf_s *lower,
FAR struct file *filep,
int cmd, unsigned long arg)
{
FAR struct sensor_rpmsg_dev_s *dev = lower->priv;
FAR struct sensor_lowerhalf_s *drv = dev->drv;
FAR struct sensor_ioctl_s *ioctl = (FAR void *)(uintptr_t)arg;
int ret = -ENOTTY;
if (drv->ops->control)
{
ret = drv->ops->control(drv, filep, cmd, arg);
}
if (ret == -ENOTTY && !(filep->f_oflags & SENSOR_REMOTE) &&
_SNIOCVALID(cmd))
{
return sensor_rpmsg_ioctl(dev, cmd, arg,
sizeof(*ioctl) + ioctl->len, true);
}
return ret;
}
static void sensor_rpmsg_data_worker(FAR void *arg)
{
FAR struct sensor_rpmsg_ept_s *sre = arg;
int ret;
nxrmutex_lock(&sre->lock);
if (sre->buffer)
{
ret = rpmsg_send_nocopy(&sre->ept, sre->buffer, sre->written);
if (ret < 0)
{
rpmsg_release_tx_buffer(&sre->ept, sre->buffer);
snerr("ERROR: push event rpmsg send failed:%d, %s\n",
ret, rpmsg_get_cpuname(sre->ept.rdev));
}
sre->buffer = NULL;
}
nxrmutex_unlock(&sre->lock);
}
static void sensor_rpmsg_push_event_one(FAR struct sensor_rpmsg_dev_s *dev,
FAR struct sensor_rpmsg_stub_s *stub,
bool flushed)
{
FAR struct sensor_rpmsg_cell_s *cell;
FAR struct sensor_rpmsg_ept_s *sre;
FAR struct sensor_rpmsg_data_s *msg;
struct sensor_ustate_s state;
uint64_t now;
bool updated;
int ret;
* to remote
*/
sre = container_of(stub->ept, struct sensor_rpmsg_ept_s, ept);
if (!stub->wakeup && !rpmsg_is_running(sre->ept.rdev))
{
return;
}
ret = file_ioctl(&stub->file, SNIOC_GET_USTATE, &state);
if (ret < 0)
{
return;
}
if (state.interval == UINT32_MAX)
{
state.interval = 0;
}
nxrmutex_lock(&sre->lock);
if (sre->buffer)
{
work_cancel(HPWORK, &sre->work);
}
for (; ; )
{
ret = file_ioctl(&stub->file, SNIOC_UPDATED, &updated);
if (ret < 0 || (!updated && !flushed))
{
break;
}
* new data, you should create or send this buffer at once.
*/
if (!sre->buffer ||
sre->written + sizeof(*cell) + state.esize > sre->space)
{
if (sre->buffer)
{
rpmsg_send_nocopy(&sre->ept, sre->buffer, sre->written);
sre->buffer = NULL;
}
msg = rpmsg_get_tx_payload_buffer(&sre->ept, &sre->space, true);
sre->buffer = msg;
if (!msg)
{
snerr("ERROR: push event get buffer failed:%s\n",
rpmsg_get_cpuname(sre->ept.rdev));
nxrmutex_unlock(&sre->lock);
return;
}
msg->command = SENSOR_RPMSG_PUBLISH;
sre->written = sizeof(*msg);
sre->expire = UINT64_MAX;
}
cell = sre->buffer + sre->written;
if (flushed)
{
flushed = false;
stub->flushing = false;
}
else
{
ret = file_read(&stub->file, cell->data,
sre->space - sre->written - sizeof(*cell));
if (ret <= 0)
{
break;
}
}
smdebug(dev->name, "rpmsg push event, "
"readcount:%d to remote:%s i:%" PRIu32 ", l:%" PRIu32,
ret, rpmsg_get_cpuname(sre->ept.rdev),
state.interval, state.latency);
cell->len = ret;
cell->cookie = stub->cookie;
cell->nbuffer = dev->lower.nbuffer;
sre->written += (sizeof(*cell) + ret + 0x7) & ~0x7;
}
* delay work to send data.
*/
now = sensor_get_timestamp();
if (sre->expire <= now && sre->buffer)
{
ret = rpmsg_send_nocopy(&sre->ept, sre->buffer, sre->written);
if (ret < 0)
{
rpmsg_release_tx_buffer(&sre->ept, sre->buffer);
snerr("ERROR: push event rpmsg send failed:%d, %s\n",
ret, rpmsg_get_cpuname(sre->ept.rdev));
}
sre->buffer = NULL;
}
else
{
if (sre->expire == UINT64_MAX ||
sre->expire - now > state.interval / 2)
{
sre->expire = now + state.interval / 2;
}
work_queue(HPWORK, &sre->work, sensor_rpmsg_data_worker, sre,
(sre->expire - now) / USEC_PER_TICK);
}
nxrmutex_unlock(&sre->lock);
}
static ssize_t sensor_rpmsg_push_event(FAR void *priv, FAR const void *data,
size_t bytes)
{
FAR struct sensor_rpmsg_dev_s *dev = priv;
FAR struct sensor_rpmsg_stub_s *stub;
FAR struct sensor_rpmsg_stub_s *stmp;
ssize_t ret;
ret = dev->push_event(dev->upper, data, bytes);
if (ret < 0)
{
return ret;
}
* is successful, and must return length of written.
*/
sensor_rpmsg_lock(dev);
list_for_every_entry_safe(&dev->stublist, stub, stmp,
struct sensor_rpmsg_stub_s, node)
{
sensor_rpmsg_push_event_one(dev, stub,
stub->flushing && bytes == 0);
}
sensor_rpmsg_unlock(dev);
return ret;
}
static void
sensor_rpmsg_notify_interval(FAR void *priv, uint32_t interval)
{
FAR struct sensor_rpmsg_dev_s *dev = priv;
dev->notify_interval(dev->upper, interval);
}
static FAR struct sensor_rpmsg_dev_s *
sensor_rpmsg_find_dev(FAR const char *path)
{
FAR struct sensor_rpmsg_dev_s *dev;
down_read(&g_dev_lock);
list_for_every_entry(&g_devlist, dev, struct sensor_rpmsg_dev_s, node)
{
if (strcmp(dev->path, path) == 0)
{
up_read(&g_dev_lock);
return dev;
}
}
up_read(&g_dev_lock);
return NULL;
}
static void sensor_rpmsg_update_config(FAR struct sensor_rpmsg_dev_s *dev,
FAR struct sensor_state_s *state)
{
if (state->esize == UINT32_MAX)
{
return;
}
if (state->min_interval != UINT32_MAX)
{
sensor_rpmsg_ioctl(dev, SNIOC_SET_INTERVAL, state->min_interval,
0, false);
}
if (state->min_latency != UINT32_MAX)
{
sensor_rpmsg_ioctl(dev, SNIOC_BATCH, state->min_latency, 0, false);
}
if (state->wakeup)
{
sensor_rpmsg_ioctl(dev, SNIOC_SET_WAKEUP, state->wakeup, 0, false);
}
}
static int sensor_rpmsg_adv_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
FAR struct sensor_rpmsg_advsub_s *msg = data;
FAR struct sensor_rpmsg_proxy_s *proxy;
FAR struct sensor_rpmsg_dev_s *dev;
struct sensor_state_s state;
int ret;
dev = sensor_rpmsg_find_dev(msg->path);
if (!dev || !dev->nsubscribers)
{
return 0;
}
state.esize = UINT32_MAX;
proxy = sensor_rpmsg_alloc_proxy(dev, ept, msg, &state);
if (!proxy)
{
snerr("ERROR: adv create proxy failed:%s\n", dev->path);
}
else
{
msg->cookie = (uint64_t)(uintptr_t)dev;
msg->command = SENSOR_RPMSG_ADVERTISE_ACK;
ret = rpmsg_send(ept, msg, len);
if (ret < 0)
{
snerr("ERROR: adv rpmsg send failed:%s, %d, %s\n",
dev->path, ret, rpmsg_get_cpuname(ept->rdev));
}
else
{
sensor_rpmsg_update_config(dev, &state);
sminfo(dev->name, "rpmsg adv proxy success, remote:%s",
rpmsg_get_cpuname(ept->rdev));
}
}
return 0;
}
static int sensor_rpmsg_advack_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
FAR struct sensor_rpmsg_advsub_s *msg = data;
FAR struct sensor_rpmsg_dev_s *dev;
dev = sensor_rpmsg_find_dev(msg->path);
if (dev && !sensor_rpmsg_alloc_stub(dev, ept, msg->cookie))
{
snerr("ERROR: advack failed:%s, %s\n", dev->path,
rpmsg_get_cpuname(ept->rdev));
}
return 0;
}
static int sensor_rpmsg_unadv_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
return 0;
}
static int sensor_rpmsg_sub_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
FAR struct sensor_rpmsg_advsub_s *msg = data;
FAR struct sensor_rpmsg_dev_s *dev;
FAR struct sensor_rpmsg_stub_s *stub;
int ret;
dev = sensor_rpmsg_find_dev(msg->path);
* following conditions:
* 1.There is no node under the current core.(/dev/uorb/xxx)
* 2.The current core has not advertised any data. nadvertisers is -1.
* 3.When the number of advertisers is 0, it is not persistent attribute.
*/
if (!dev || dev->nadvertisers < 0 || (dev->nadvertisers == 0 &&
!dev->lower.persist))
{
return 0;
}
stub = sensor_rpmsg_alloc_stub(dev, ept, msg->cookie);
if (!stub)
{
snerr("ERROR: sub alloc stub failed:%s\n", dev->path);
}
else
{
msg->cookie = (uint64_t)(uintptr_t)dev;
msg->command = SENSOR_RPMSG_SUBSCRIBE_ACK;
msg->nbuffer = dev->lower.nbuffer;
msg->persist = dev->lower.persist;
ret = rpmsg_send(ept, msg, len);
if (ret < 0)
{
sensor_rpmsg_lock(dev);
sensor_rpmsg_free_stub(stub);
sensor_rpmsg_unlock(dev);
snerr("ERROR: sub rpmsg send failed:%s, %d, %s\n",
dev->path, ret, rpmsg_get_cpuname(ept->rdev));
}
}
return 0;
}
static int sensor_rpmsg_suback_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
FAR struct sensor_rpmsg_advsub_s *msg = data;
FAR struct sensor_rpmsg_dev_s *dev;
struct sensor_state_s state;
state.esize = UINT32_MAX;
dev = sensor_rpmsg_find_dev(msg->path);
if (dev && (!dev->nsubscribers ||
!sensor_rpmsg_alloc_proxy(dev, ept, msg, &state)))
{
sensor_rpmsg_advsub_one(dev, ept, SENSOR_RPMSG_UNSUBSCRIBE);
snerr("ERROR: suback failed:%s\n", dev->path);
}
else
{
sensor_rpmsg_update_config(dev, &state);
sminfo(dev->name, "rpmsg suback success, remote:%s",
rpmsg_get_cpuname(ept->rdev));
}
return 0;
}
static int sensor_rpmsg_unsub_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
FAR struct sensor_rpmsg_advsub_s *msg = data;
FAR struct sensor_rpmsg_dev_s *dev;
FAR struct sensor_rpmsg_stub_s *stub;
dev = sensor_rpmsg_find_dev(msg->path);
if (!dev)
{
return 0;
}
sensor_rpmsg_lock(dev);
list_for_every_entry(&dev->stublist, stub,
struct sensor_rpmsg_stub_s, node)
{
if (stub->ept == ept && stub->cookie == msg->cookie)
{
sensor_rpmsg_free_stub(stub);
break;
}
}
sensor_rpmsg_unlock(dev);
return 0;
}
static int sensor_rpmsg_publish_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
FAR struct sensor_rpmsg_data_s *msg = data;
FAR struct sensor_rpmsg_cell_s *cell;
FAR struct sensor_rpmsg_stub_s *stub;
FAR struct sensor_rpmsg_stub_s *stmp;
FAR struct sensor_rpmsg_dev_s *dev;
size_t written = sizeof(*msg);
while (written < len)
{
cell = (FAR struct sensor_rpmsg_cell_s *)
((FAR char *)data + written);
dev = (FAR struct sensor_rpmsg_dev_s *)(uintptr_t)cell->cookie;
if (cell->nbuffer > dev->lower.nbuffer)
{
struct file file;
int ret;
ret = file_open(&file, dev->path, SENSOR_REMOTE | O_CLOEXEC);
if (ret >= 0)
{
ret = file_ioctl(&file, SNIOC_SET_BUFFER_NUMBER,
cell->nbuffer);
if (ret >= 0)
{
dev->lower.nbuffer = cell->nbuffer;
}
file_close(&file);
}
}
dev->push_event(dev->upper, cell->data, cell->len);
* receive the message. When the subscribed core publishes a new
* message, it will take away the message published by the remote core,
* so all stublist information needs to be updated.
*/
sensor_rpmsg_lock(dev);
list_for_every_entry_safe(&dev->stublist, stub, stmp,
struct sensor_rpmsg_stub_s, node)
{
file_read(&stub->file, NULL, cell->len);
}
sensor_rpmsg_unlock(dev);
smdebug(dev->name, "rpmsg receive data: cnt:%" PRIu32 ", "
"from remote:%s", cell->len, rpmsg_get_cpuname(ept->rdev));
written += sizeof(*cell) + cell->len + 0x7;
written &= ~0x7;
}
return 0;
}
static int sensor_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
FAR struct sensor_rpmsg_ioctl_s *msg = data;
FAR struct sensor_rpmsg_stub_s *stub;
FAR struct sensor_rpmsg_stub_s *stmp;
FAR struct sensor_rpmsg_dev_s *dev;
unsigned long arg;
int ret;
arg = msg->arglen > 0 ? (unsigned long)(uintptr_t)msg->arg :
*(FAR uint64_t *)msg->arg;
dev = (FAR struct sensor_rpmsg_dev_s *)(uintptr_t)msg->proxy;
sensor_rpmsg_lock(dev);
list_for_every_entry_safe(&dev->stublist, stub, stmp,
struct sensor_rpmsg_stub_s, node)
{
if (stub->ept == ept)
{
msg->result = file_ioctl(&stub->file, msg->request, arg);
if (msg->result >= 0 && msg->request == SNIOC_FLUSH)
{
sminfo(dev->name, "receiving flush request");
stub->flushing = true;
}
if (msg->request == SNIOC_SET_WAKEUP)
{
stub->wakeup = arg;
sminfo(dev->name, "receiving wakeup update:%d", stub->wakeup);
}
if (msg->cookie)
{
msg->command = SENSOR_RPMSG_IOCTL_ACK;
ret = rpmsg_send(ept, msg, len);
if (ret < 0)
{
snerr("ERROR: ioctl rpmsg send failed:%s, %d, %s\n",
dev->path, ret, rpmsg_get_cpuname(ept->rdev));
}
}
break;
}
}
sensor_rpmsg_unlock(dev);
return 0;
}
static int sensor_rpmsg_ioctlack_handler(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len,
uint32_t src, FAR void *priv)
{
FAR struct sensor_rpmsg_ioctl_cookie_s *cookie;
FAR struct sensor_rpmsg_ioctl_s *msg = data;
cookie = (FAR struct sensor_rpmsg_ioctl_cookie_s *)
(uintptr_t)msg->cookie;
cookie->result = msg->result;
if (msg->result >= 0 && msg->arglen > 0)
{
memcpy(cookie->data, msg->arg, msg->arglen);
}
rpmsg_post(ept, &cookie->sem);
return 0;
}
static int sensor_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len, uint32_t src,
FAR void *priv)
{
FAR struct sensor_rpmsg_advsub_s *msg = data;
if (msg->command < sizeof(g_sensor_rpmsg_handler) /
sizeof(g_sensor_rpmsg_handler[0]))
{
return g_sensor_rpmsg_handler[msg->command](ept, data, len, src, priv);
}
return -EINVAL;
}
static void sensor_rpmsg_bound_worker(FAR void *arg)
{
FAR struct sensor_rpmsg_ept_s *sre = arg;
FAR struct sensor_rpmsg_dev_s *dev;
down_read(&g_dev_lock);
list_for_every_entry(&g_devlist, dev,
struct sensor_rpmsg_dev_s, node)
{
sensor_rpmsg_lock(dev);
if (dev->nadvertisers > 0)
{
sensor_rpmsg_advsub_one(dev, &sre->ept, SENSOR_RPMSG_ADVERTISE);
}
if (dev->nsubscribers > 0)
{
sensor_rpmsg_advsub_one(dev, &sre->ept, SENSOR_RPMSG_SUBSCRIBE);
}
sensor_rpmsg_unlock(dev);
}
up_read(&g_dev_lock);
}
static void sensor_rpmsg_device_ns_bound(FAR struct rpmsg_endpoint *ept)
{
FAR struct sensor_rpmsg_ept_s *sre;
sre = container_of(ept, struct sensor_rpmsg_ept_s, ept);
down_write(&g_ept_lock);
list_add_tail(&g_eptlist, &sre->node);
up_write(&g_ept_lock);
work_queue(HPWORK, &sre->bound_work, sensor_rpmsg_bound_worker, sre, 0);
}
static void sensor_rpmsg_ept_release(FAR struct rpmsg_endpoint *ept)
{
FAR struct sensor_rpmsg_ept_s *sre;
FAR struct sensor_rpmsg_dev_s *dev;
FAR struct sensor_rpmsg_stub_s *stub;
FAR struct sensor_rpmsg_proxy_s *proxy;
sre = container_of(ept, struct sensor_rpmsg_ept_s, ept);
* destoryed.
*/
down_read(&g_dev_lock);
list_for_every_entry(&g_devlist, dev,
struct sensor_rpmsg_dev_s, node)
{
sensor_rpmsg_lock(dev);
list_for_every_entry(&dev->proxylist, proxy,
struct sensor_rpmsg_proxy_s, node)
{
if (proxy->ept == ept)
{
sensor_rpmsg_free_proxy(dev, proxy);
break;
}
}
list_for_every_entry(&dev->stublist, stub,
struct sensor_rpmsg_stub_s, node)
{
if (stub->ept == ept)
{
sensor_rpmsg_free_stub(stub);
break;
}
}
sensor_rpmsg_unlock(dev);
}
up_read(&g_dev_lock);
down_write(&g_ept_lock);
if (list_in_list(&sre->node))
{
list_delete(&sre->node);
}
up_write(&g_ept_lock);
nxrmutex_destroy(&sre->lock);
kmm_free(sre);
}
static void sensor_rpmsg_device_created(FAR struct rpmsg_device *rdev,
FAR void *priv)
{
FAR struct sensor_rpmsg_ept_s *sre;
sre = kmm_zalloc(sizeof(*sre));
if (!sre)
{
return;
}
sre->ept.priv = sre;
nxrmutex_init(&sre->lock);
sre->ept.ns_bound_cb = sensor_rpmsg_device_ns_bound;
sre->ept.release_cb = sensor_rpmsg_ept_release;
if (rpmsg_create_ept(&sre->ept, rdev, SENSOR_RPMSG_EPT_NAME,
RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
sensor_rpmsg_ept_cb,
rpmsg_destroy_ept) < 0)
{
nxrmutex_destroy(&sre->lock);
kmm_free(sre);
}
}
* Public Functions
****************************************************************************/
* Name: sensor_rpmsg_register
*
* Description:
* This function registers rpmsg takeover for the real lower half, and
* initialize rpmsg resource.
*
* Input Parameters:
* lower - The instance of lower half sensor driver.
* path - The path of character node, ex: /dev/uorb/xxx.
*
* Returned Value:
* The takeover rpmsg lowerhalf returned on success, NULL on failure.
*
****************************************************************************/
FAR struct sensor_lowerhalf_s *
sensor_rpmsg_register(FAR struct sensor_lowerhalf_s *lower,
FAR const char *path)
{
FAR struct sensor_rpmsg_ept_s *sre;
FAR struct sensor_rpmsg_dev_s *dev;
size_t size;
if (lower->ops->fetch)
{
return lower;
}
size = strlen(path);
dev = kmm_zalloc(sizeof(*dev) + size);
if (!dev)
{
return NULL;
}
nxsem_init(&dev->proxysem, 0, 0);
list_initialize(&dev->stublist);
list_initialize(&dev->proxylist);
strlcpy(dev->path, path, size + 1);
dev->name = basename(dev->path);
dev->nadvertisers = lower->ops->activate ? 1 : -1;
dev->push_event = lower->push_event;
dev->notify_interval = lower->notify_interval;
dev->upper = lower->priv;
lower->push_event = sensor_rpmsg_push_event;
lower->notify_interval = sensor_rpmsg_notify_interval;
lower->priv = dev;
memcpy(&dev->lower, lower, sizeof(*lower));
dev->lower.ops = &g_sensor_rpmsg_ops;
dev->drv = lower;
down_write(&g_dev_lock);
list_add_tail(&g_devlist, &dev->node);
up_write(&g_dev_lock);
if (lower->ops->activate)
{
down_read(&g_ept_lock);
list_for_every_entry(&g_eptlist, sre, struct sensor_rpmsg_ept_s,
node)
{
sensor_rpmsg_advsub_one(dev, &sre->ept, SENSOR_RPMSG_ADVERTISE);
}
up_read(&g_ept_lock);
}
return &dev->lower;
}
* Name: sensor_rpmsg_unregister
*
* Description:
* This function unregisters rpmsg takeover for the real lower half, and
* release rpmsg resource. This API corresponds to sensor_rpmsg_register.
*
* Input Parameters:
* lower - The instance of lower half sensor driver.
*
* Returned Value:
* The takeover rpmsg lowerhalf returned on success, NULL on failure.
****************************************************************************/
FAR struct sensor_lowerhalf_s *
sensor_rpmsg_unregister(FAR struct sensor_lowerhalf_s *lower)
{
FAR struct sensor_rpmsg_dev_s *dev = lower->priv;
if (dev->nsubscribers != 0)
{
return NULL;
}
down_write(&g_dev_lock);
list_delete(&dev->node);
up_write(&g_dev_lock);
nxsem_destroy(&dev->proxysem);
lower->priv = dev->upper;
kmm_free(dev);
return lower;
}
* Name: sensor_rpmsg_initialize
*
* Description:
* This function initializes the context of sensor rpmsg, registers
* rpmsg callback and prepares enviroment to intercat with remote sensor.
*
* Returned Value:
* OK on success; A negated errno value is returned on any failure.
*
****************************************************************************/
int sensor_rpmsg_initialize(void)
{
return rpmsg_register_callback(NULL, sensor_rpmsg_device_created,
NULL, NULL, NULL);
}