839 lines
24 KiB
C
839 lines
24 KiB
C
/****************************************************************************
|
|
* drivers/timers/rpmsg_rtc.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 <nuttx/config.h>
|
|
|
|
#include <nuttx/nuttx.h>
|
|
#include <nuttx/list.h>
|
|
#include <nuttx/clock.h>
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/rpmsg/rpmsg.h>
|
|
#include <nuttx/mutex.h>
|
|
#include <nuttx/timers/rpmsg_rtc.h>
|
|
#include <nuttx/timers/arch_rtc.h>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include "clock/clock.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor definitions
|
|
****************************************************************************/
|
|
|
|
#define RPMSG_RTC_EPT_NAME "rpmsg-rtc"
|
|
|
|
#define RPMSG_RTC_SET 0
|
|
#define RPMSG_RTC_GET 1
|
|
#define RPMSG_RTC_ALARM_SET 2
|
|
#define RPMSG_RTC_ALARM_CANCEL 3
|
|
#define RPMSG_RTC_ALARM_FIRE 4
|
|
#define RPMSG_RTC_SYNC 5
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
begin_packed_struct struct rpmsg_rtc_header_s
|
|
{
|
|
uint32_t command;
|
|
int32_t result;
|
|
uint64_t cookie;
|
|
} end_packed_struct;
|
|
|
|
begin_packed_struct struct rpmsg_rtc_set_s
|
|
{
|
|
struct rpmsg_rtc_header_s header;
|
|
int64_t base_sec;
|
|
int64_t sec;
|
|
int32_t nsec;
|
|
int32_t base_nsec;
|
|
} end_packed_struct;
|
|
|
|
#define rpmsg_rtc_get_s rpmsg_rtc_set_s
|
|
|
|
begin_packed_struct struct rpmsg_rtc_alarm_set_s
|
|
{
|
|
struct rpmsg_rtc_header_s header;
|
|
int64_t sec;
|
|
int32_t nsec;
|
|
int32_t id;
|
|
} end_packed_struct;
|
|
|
|
begin_packed_struct struct rpmsg_rtc_alarm_cancel_s
|
|
{
|
|
struct rpmsg_rtc_header_s header;
|
|
int32_t id;
|
|
} end_packed_struct;
|
|
|
|
#define rpmsg_rtc_alarm_fire_s rpmsg_rtc_alarm_cancel_s
|
|
|
|
#ifndef CONFIG_RTC_RPMSG_SERVER
|
|
struct rpmsg_rtc_cookie_s
|
|
{
|
|
FAR struct rpmsg_rtc_header_s *msg;
|
|
sem_t sem;
|
|
};
|
|
|
|
/* This is the private type for the RTC state. It must be cast compatible
|
|
* with struct rtc_lowerhalf_s.
|
|
*/
|
|
|
|
struct rpmsg_rtc_lowerhalf_s
|
|
{
|
|
/* This is the contained reference to the read-only, lower-half
|
|
* operations vtable (which may lie in FLASH or ROM)
|
|
*/
|
|
|
|
FAR const struct rtc_ops_s *ops;
|
|
|
|
/* Data following is private to this driver and not visible outside of
|
|
* this file.
|
|
*/
|
|
|
|
struct rpmsg_endpoint ept;
|
|
|
|
#ifdef CONFIG_RTC_ALARM
|
|
struct lower_setalarm_s alarminfo[CONFIG_RTC_NALARMS];
|
|
#endif
|
|
};
|
|
#else
|
|
struct rpmsg_rtc_server_s
|
|
{
|
|
FAR struct rtc_ops_s *ops;
|
|
FAR struct rtc_lowerhalf_s *lower;
|
|
struct list_node list;
|
|
mutex_t lock;
|
|
};
|
|
|
|
struct rpmsg_rtc_client_s
|
|
{
|
|
struct list_node node;
|
|
struct rpmsg_endpoint ept;
|
|
};
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_RTC_RPMSG_SERVER
|
|
static void rpmsg_rtc_device_created(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv);
|
|
static void rpmsg_rtc_device_destroy(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv);
|
|
static void rpmsg_rtc_alarm_fire_handler(FAR struct rpmsg_endpoint *ept,
|
|
FAR void *data, size_t len, uint32_t src, FAR void *priv);
|
|
static int rpmsg_rtc_ept_cb(FAR struct rpmsg_endpoint *ept, FAR void *data,
|
|
size_t len, uint32_t src, FAR void *priv);
|
|
|
|
static int rpmsg_rtc_send_recv(FAR struct rpmsg_rtc_lowerhalf_s *lower,
|
|
uint32_t command, FAR struct rpmsg_rtc_header_s *msg, int len);
|
|
static int rpmsg_rtc_rdtime(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR struct rtc_time *rtctime);
|
|
static int rpmsg_rtc_settime(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct rtc_time *rtctime);
|
|
static bool rpmsg_rtc_havesettime(FAR struct rtc_lowerhalf_s *lower);
|
|
|
|
#ifdef CONFIG_RTC_ALARM
|
|
static int rpmsg_rtc_setalarm(FAR struct rtc_lowerhalf_s *lower_,
|
|
FAR const struct lower_setalarm_s *alarminfo);
|
|
static int rpmsg_rtc_setrelative(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct lower_setrelative_s *relinfo);
|
|
static int rpmsg_rtc_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
|
|
int alarmid);
|
|
static int rpmsg_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower_,
|
|
FAR struct lower_rdalarm_s *alarminfo);
|
|
#endif
|
|
#else
|
|
static int rpmsg_rtc_server_rdtime(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR struct rtc_time *rtctime);
|
|
static int rpmsg_rtc_server_settime(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct rtc_time *rtctime);
|
|
static bool rpmsg_rtc_server_havesettime(FAR struct rtc_lowerhalf_s *lower);
|
|
|
|
#ifdef CONFIG_RTC_ALARM
|
|
static int rpmsg_rtc_server_setalarm(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct lower_setalarm_s *alarminfo);
|
|
static int rpmsg_rtc_server_setrelative(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct lower_setrelative_s *relinfo);
|
|
static int rpmsg_rtc_server_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
|
|
int alarmid);
|
|
static int rpmsg_rtc_server_rdalarm(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR struct lower_rdalarm_s *alarminfo);
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTC_PERIODIC
|
|
static int rpmsg_rtc_server_setperiodic(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct lower_setperiodic_s *alarminfo);
|
|
|
|
static int rpmsg_rtc_server_cancelperiodic(
|
|
FAR struct rtc_lowerhalf_s *lower, int alarmid);
|
|
#endif
|
|
#ifdef CONFIG_RTC_IOCTL
|
|
static int rpmsg_rtc_server_ioctl(FAR struct rtc_lowerhalf_s *lower,
|
|
int cmd, unsigned long arg);
|
|
#endif
|
|
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
|
|
static int rpmsg_rtc_server_destroy(FAR struct rtc_lowerhalf_s *lower);
|
|
#endif
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_RTC_RPMSG_SERVER
|
|
static const struct rtc_ops_s g_rpmsg_rtc_ops =
|
|
{
|
|
rpmsg_rtc_rdtime,
|
|
rpmsg_rtc_settime,
|
|
rpmsg_rtc_havesettime,
|
|
#ifdef CONFIG_RTC_ALARM
|
|
rpmsg_rtc_setalarm,
|
|
rpmsg_rtc_setrelative,
|
|
rpmsg_rtc_cancelalarm,
|
|
rpmsg_rtc_rdalarm,
|
|
#endif
|
|
};
|
|
#else
|
|
static struct rtc_ops_s g_rpmsg_rtc_server_ops =
|
|
{
|
|
rpmsg_rtc_server_rdtime,
|
|
rpmsg_rtc_server_settime,
|
|
rpmsg_rtc_server_havesettime,
|
|
#ifdef CONFIG_RTC_ALARM
|
|
rpmsg_rtc_server_setalarm,
|
|
rpmsg_rtc_server_setrelative,
|
|
rpmsg_rtc_server_cancelalarm,
|
|
rpmsg_rtc_server_rdalarm,
|
|
#endif
|
|
#ifdef CONFIG_RTC_PERIODIC
|
|
rpmsg_rtc_server_setperiodic,
|
|
rpmsg_rtc_server_cancelperiodic,
|
|
#endif
|
|
#ifdef CONFIG_RTC_IOCTL
|
|
rpmsg_rtc_server_ioctl,
|
|
#endif
|
|
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
|
|
rpmsg_rtc_server_destroy,
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_RTC_RPMSG_SERVER
|
|
static void rpmsg_rtc_device_created(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv)
|
|
{
|
|
FAR struct rpmsg_rtc_lowerhalf_s *lower = priv;
|
|
|
|
if (strcmp(CONFIG_RTC_RPMSG_SERVER_NAME,
|
|
rpmsg_get_cpuname(rdev)) == 0)
|
|
{
|
|
lower->ept.priv = lower;
|
|
|
|
rpmsg_create_ept(&lower->ept, rdev, RPMSG_RTC_EPT_NAME,
|
|
RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
|
|
rpmsg_rtc_ept_cb, NULL);
|
|
}
|
|
}
|
|
|
|
static void rpmsg_rtc_device_destroy(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv)
|
|
{
|
|
FAR struct rpmsg_rtc_lowerhalf_s *lower = priv;
|
|
|
|
if (strcmp(CONFIG_RTC_RPMSG_SERVER_NAME,
|
|
rpmsg_get_cpuname(rdev)) == 0)
|
|
{
|
|
rpmsg_destroy_ept(&lower->ept);
|
|
}
|
|
}
|
|
|
|
static void rpmsg_rtc_alarm_fire_handler(FAR struct rpmsg_endpoint *ept,
|
|
FAR void *data, size_t len,
|
|
uint32_t src, FAR void *priv)
|
|
{
|
|
#ifdef CONFIG_RTC_ALARM
|
|
FAR struct rpmsg_rtc_lowerhalf_s *lower = priv;
|
|
FAR struct rpmsg_rtc_alarm_fire_s *msg = data;
|
|
FAR struct lower_setalarm_s *alarminfo = &lower->alarminfo[msg->id];
|
|
|
|
alarminfo->cb(alarminfo->priv, alarminfo->id);
|
|
#endif
|
|
}
|
|
|
|
static int rpmsg_rtc_ept_cb(FAR struct rpmsg_endpoint *ept, FAR void *data,
|
|
size_t len, uint32_t src, FAR void *priv)
|
|
{
|
|
FAR struct rpmsg_rtc_header_s *header = data;
|
|
FAR struct rpmsg_rtc_cookie_s *cookie =
|
|
(FAR struct rpmsg_rtc_cookie_s *)(uintptr_t)header->cookie;
|
|
|
|
switch (header->command)
|
|
{
|
|
case RPMSG_RTC_ALARM_FIRE:
|
|
rpmsg_rtc_alarm_fire_handler(ept, data, len, src, priv);
|
|
break;
|
|
|
|
case RPMSG_RTC_SYNC:
|
|
{
|
|
struct rpmsg_rtc_set_s *msg = data;
|
|
|
|
#ifdef CONFIG_RTC_RPMSG_SYNC_BASETIME
|
|
g_basetime.tv_sec = msg->base_sec;
|
|
g_basetime.tv_nsec = msg->base_nsec;
|
|
#else
|
|
struct timespec tp;
|
|
|
|
tp.tv_sec = msg->sec;
|
|
tp.tv_nsec = msg->nsec;
|
|
|
|
clock_synchronize(&tp);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (cookie)
|
|
{
|
|
memcpy(cookie->msg, data, len);
|
|
nxsem_post(&cookie->sem);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rpmsg_rtc_send_recv(FAR struct rpmsg_rtc_lowerhalf_s *lower,
|
|
uint32_t command,
|
|
FAR struct rpmsg_rtc_header_s *msg, int len)
|
|
{
|
|
struct rpmsg_rtc_cookie_s cookie;
|
|
int ret;
|
|
|
|
nxsem_init(&cookie.sem, 0, 0);
|
|
cookie.msg = msg;
|
|
|
|
msg->command = command;
|
|
msg->result = -ENXIO;
|
|
msg->cookie = (uintptr_t)&cookie;
|
|
|
|
ret = rpmsg_send(&lower->ept, msg, len);
|
|
if (ret < 0)
|
|
{
|
|
goto fail;
|
|
}
|
|
|
|
ret = nxsem_wait_uninterruptible(&cookie.sem);
|
|
if (ret == 0)
|
|
{
|
|
ret = msg->result;
|
|
}
|
|
|
|
fail:
|
|
nxsem_destroy(&cookie.sem);
|
|
return ret;
|
|
}
|
|
|
|
static int rpmsg_rtc_rdtime(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR struct rtc_time *rtctime)
|
|
{
|
|
struct rpmsg_rtc_get_s msg;
|
|
int ret;
|
|
|
|
ret = rpmsg_rtc_send_recv((FAR struct rpmsg_rtc_lowerhalf_s *)lower,
|
|
RPMSG_RTC_GET, (struct rpmsg_rtc_header_s *)&msg, sizeof(msg));
|
|
if (ret >= 0)
|
|
{
|
|
time_t time = msg.sec;
|
|
gmtime_r(&time, (FAR struct tm *)rtctime);
|
|
rtctime->tm_nsec = msg.nsec;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int rpmsg_rtc_settime(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct rtc_time *rtctime)
|
|
{
|
|
struct rpmsg_rtc_set_s msg;
|
|
|
|
msg.sec = timegm((FAR struct tm *)rtctime);
|
|
msg.nsec = rtctime->tm_nsec;
|
|
|
|
return rpmsg_rtc_send_recv((FAR struct rpmsg_rtc_lowerhalf_s *)lower,
|
|
RPMSG_RTC_SET, (struct rpmsg_rtc_header_s *)&msg, sizeof(msg));
|
|
}
|
|
|
|
static bool rpmsg_rtc_havesettime(FAR struct rtc_lowerhalf_s *lower)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
#ifdef CONFIG_RTC_ALARM
|
|
static int rpmsg_rtc_setalarm(FAR struct rtc_lowerhalf_s *lower_,
|
|
FAR const struct lower_setalarm_s *alarminfo)
|
|
{
|
|
FAR struct rpmsg_rtc_lowerhalf_s *lower =
|
|
(FAR struct rpmsg_rtc_lowerhalf_s *)lower_;
|
|
struct rpmsg_rtc_alarm_set_s msg;
|
|
int ret;
|
|
|
|
msg.id = alarminfo->id;
|
|
msg.sec = timegm((FAR struct tm *)&alarminfo->time);
|
|
msg.nsec = alarminfo->time.tm_nsec;
|
|
|
|
ret = rpmsg_rtc_send_recv(lower, RPMSG_RTC_ALARM_SET,
|
|
(struct rpmsg_rtc_header_s *)&msg, sizeof(msg));
|
|
if (ret >= 0)
|
|
{
|
|
lower->alarminfo[alarminfo->id] = *alarminfo;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
rpmsg_rtc_setrelative(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct lower_setrelative_s *relinfo)
|
|
{
|
|
struct lower_setalarm_s alarminfo;
|
|
time_t time;
|
|
|
|
alarminfo.id = relinfo->id;
|
|
alarminfo.cb = relinfo->cb;
|
|
alarminfo.priv = relinfo->priv;
|
|
|
|
rpmsg_rtc_rdtime(lower, &alarminfo.time);
|
|
time = timegm((FAR struct tm *)&alarminfo.time);
|
|
time = time + relinfo->reltime;
|
|
gmtime_r(&time, (FAR struct tm *)&alarminfo.time);
|
|
|
|
return rpmsg_rtc_setalarm(lower, &alarminfo);
|
|
}
|
|
|
|
static int rpmsg_rtc_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
|
|
int alarmid)
|
|
{
|
|
struct rpmsg_rtc_alarm_cancel_s msg;
|
|
|
|
msg.id = alarmid;
|
|
return rpmsg_rtc_send_recv((FAR struct rpmsg_rtc_lowerhalf_s *)lower,
|
|
RPMSG_RTC_ALARM_CANCEL, (struct rpmsg_rtc_header_s *)&msg,
|
|
sizeof(msg));
|
|
}
|
|
|
|
static int rpmsg_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower_,
|
|
FAR struct lower_rdalarm_s *alarminfo)
|
|
{
|
|
FAR struct rpmsg_rtc_lowerhalf_s *lower =
|
|
(FAR struct rpmsg_rtc_lowerhalf_s *)lower_;
|
|
|
|
*alarminfo->time = lower->alarminfo[alarminfo->id].time;
|
|
return 0;
|
|
}
|
|
#endif
|
|
#else
|
|
static int rpmsg_rtc_server_rdtime(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR struct rtc_time *rtctime)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->rdtime(server->lower, rtctime);
|
|
}
|
|
|
|
static int rpmsg_rtc_server_settime(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct rtc_time *rtctime)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
FAR struct rpmsg_rtc_client_s *client;
|
|
FAR struct list_node *node;
|
|
struct rpmsg_rtc_set_s msg;
|
|
int ret;
|
|
|
|
ret = server->lower->ops->settime(server->lower, rtctime);
|
|
if (ret >= 0)
|
|
{
|
|
msg.sec = timegm((FAR struct tm *)rtctime);
|
|
msg.nsec = rtctime->tm_nsec;
|
|
msg.header.command = RPMSG_RTC_SYNC;
|
|
|
|
if (ret == 0)
|
|
{
|
|
struct timespec tp;
|
|
|
|
tp.tv_sec = msg.sec;
|
|
tp.tv_nsec = msg.nsec;
|
|
clock_synchronize(&tp);
|
|
|
|
ret = 1; /* Request the upper half skip clock synchronize */
|
|
}
|
|
|
|
msg.base_sec = g_basetime.tv_sec;
|
|
msg.base_nsec = g_basetime.tv_nsec;
|
|
|
|
nxmutex_lock(&server->lock);
|
|
|
|
list_for_every(&server->list, node)
|
|
{
|
|
client = (FAR struct rpmsg_rtc_client_s *)node;
|
|
rpmsg_send(&client->ept, &msg, sizeof(msg));
|
|
}
|
|
|
|
nxmutex_unlock(&server->lock);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool rpmsg_rtc_server_havesettime(FAR struct rtc_lowerhalf_s *lower)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->havesettime(server->lower);
|
|
}
|
|
|
|
#ifdef CONFIG_RTC_ALARM
|
|
static int rpmsg_rtc_server_setalarm(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct lower_setalarm_s *alarminfo)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->setalarm(server->lower, alarminfo);
|
|
}
|
|
|
|
static int rpmsg_rtc_server_setrelative(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct lower_setrelative_s *relinfo)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->setrelative(server->lower, relinfo);
|
|
}
|
|
|
|
static int rpmsg_rtc_server_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
|
|
int alarmid)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->cancelalarm(server->lower, alarmid);
|
|
}
|
|
|
|
static int rpmsg_rtc_server_rdalarm(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR struct lower_rdalarm_s *alarminfo)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->rdalarm(server->lower, alarminfo);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTC_PERIODIC
|
|
static int rpmsg_rtc_server_setperiodic(FAR struct rtc_lowerhalf_s *lower,
|
|
FAR const struct lower_setperiodic_s *alarminfo)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->setperiodic(server->lower, alarminfo);
|
|
}
|
|
|
|
static int rpmsg_rtc_server_cancelperiodic(
|
|
FAR struct rtc_lowerhalf_s *lower, int alarmid)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->cancelperiodic(server->lower, alarmid);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTC_IOCTL
|
|
static int rpmsg_rtc_server_ioctl(FAR struct rtc_lowerhalf_s *lower,
|
|
int cmd, unsigned long arg)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
|
|
return server->lower->ops->ioctl(server->lower, cmd, arg);
|
|
}
|
|
#endif
|
|
|
|
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
|
|
static int rpmsg_rtc_server_destroy(FAR struct rtc_lowerhalf_s *lower)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server =
|
|
(FAR struct rpmsg_rtc_server_s *)lower;
|
|
FAR struct rpmsg_rtc_client_s *client;
|
|
FAR struct list_node *node;
|
|
FAR struct list_node *temp;
|
|
int ret;
|
|
|
|
ret = server->lower->ops->destroy(server->lower);
|
|
if (ret >= 0)
|
|
{
|
|
list_for_every_safe(&server->list, node, temp)
|
|
{
|
|
client = (FAR struct rpmsg_rtc_client_s *)node;
|
|
list_delete(&client->node);
|
|
rpmsg_destroy_ept(&client->ept);
|
|
kmm_free(client);
|
|
}
|
|
|
|
kmm_free(server);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTC_ALARM
|
|
static void rpmsg_rtc_server_alarm_cb(FAR void *priv, int alarmid)
|
|
{
|
|
FAR struct rpmsg_rtc_client_s *client = priv;
|
|
struct rpmsg_rtc_alarm_fire_s msg;
|
|
|
|
msg.header.command = RPMSG_RTC_ALARM_FIRE;
|
|
msg.id = alarmid;
|
|
|
|
rpmsg_send(&client->ept, &msg, sizeof(msg));
|
|
}
|
|
#endif
|
|
|
|
static int rpmsg_rtc_server_ept_cb(FAR struct rpmsg_endpoint *ept,
|
|
FAR void *data, size_t len, uint32_t src,
|
|
FAR void *priv)
|
|
{
|
|
FAR struct rpmsg_rtc_header_s *header = data;
|
|
|
|
switch (header->command)
|
|
{
|
|
case RPMSG_RTC_GET:
|
|
{
|
|
FAR struct rpmsg_rtc_get_s *msg = data;
|
|
struct rtc_time rtctime;
|
|
|
|
header->result = rpmsg_rtc_server_rdtime(priv, &rtctime);
|
|
|
|
msg->sec = timegm((FAR struct tm *)&rtctime);
|
|
msg->nsec = rtctime.tm_nsec;
|
|
return rpmsg_send(ept, msg, sizeof(*msg));
|
|
}
|
|
|
|
case RPMSG_RTC_SET:
|
|
{
|
|
FAR struct rpmsg_rtc_set_s *msg = data;
|
|
struct rtc_time rtctime;
|
|
time_t time = msg->sec;
|
|
|
|
gmtime_r(&time, (FAR struct tm *)&rtctime);
|
|
rtctime.tm_nsec = msg->nsec;
|
|
|
|
header->result = rpmsg_rtc_server_settime(priv, &rtctime);
|
|
return rpmsg_send(ept, msg, sizeof(*msg));
|
|
}
|
|
|
|
#ifdef CONFIG_RTC_ALARM
|
|
case RPMSG_RTC_ALARM_SET:
|
|
{
|
|
FAR struct rpmsg_rtc_client_s *client = container_of(ept,
|
|
struct rpmsg_rtc_client_s, ept);
|
|
FAR struct rpmsg_rtc_alarm_set_s *msg = data;
|
|
time_t time = msg->sec;
|
|
struct lower_setalarm_s alarminfo;
|
|
|
|
alarminfo.id = msg->id;
|
|
alarminfo.cb = rpmsg_rtc_server_alarm_cb;
|
|
alarminfo.priv = client;
|
|
|
|
gmtime_r(&time, (FAR struct tm *)&alarminfo.time);
|
|
alarminfo.time.tm_nsec = msg->nsec;
|
|
header->result = rpmsg_rtc_server_setalarm(priv, &alarminfo);
|
|
return rpmsg_send(ept, msg, sizeof(*msg));
|
|
}
|
|
|
|
case RPMSG_RTC_ALARM_CANCEL:
|
|
{
|
|
FAR struct rpmsg_rtc_alarm_cancel_s *msg = data;
|
|
header->result = rpmsg_rtc_server_cancelalarm(priv, msg->id);
|
|
return rpmsg_send(ept, msg, sizeof(*msg));
|
|
}
|
|
#endif
|
|
|
|
default:
|
|
header->result = -ENOSYS;
|
|
return rpmsg_send(ept, header, sizeof(*header));
|
|
}
|
|
}
|
|
|
|
static bool rpmsg_rtc_server_ns_match(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv,
|
|
FAR const char *name,
|
|
uint32_t dest)
|
|
{
|
|
return !strcmp(name, RPMSG_RTC_EPT_NAME);
|
|
}
|
|
|
|
static void rpmsg_rtc_server_ept_release(FAR struct rpmsg_endpoint *ept)
|
|
{
|
|
FAR struct rpmsg_rtc_client_s *client = container_of(ept,
|
|
struct rpmsg_rtc_client_s, ept);
|
|
FAR struct rpmsg_rtc_server_s *server = ept->priv;
|
|
|
|
nxmutex_lock(&server->lock);
|
|
list_delete(&client->node);
|
|
nxmutex_unlock(&server->lock);
|
|
kmm_free(client);
|
|
}
|
|
|
|
static void rpmsg_rtc_server_ns_bind(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv,
|
|
FAR const char *name,
|
|
uint32_t dest)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server = priv;
|
|
FAR struct rpmsg_rtc_client_s *client;
|
|
struct rpmsg_rtc_set_s msg;
|
|
struct rtc_time rtctime;
|
|
|
|
client = kmm_zalloc(sizeof(*client));
|
|
if (client == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
client->ept.priv = server;
|
|
client->ept.release_cb = rpmsg_rtc_server_ept_release;
|
|
|
|
if (rpmsg_create_ept(&client->ept, rdev, RPMSG_RTC_EPT_NAME,
|
|
RPMSG_ADDR_ANY, dest,
|
|
rpmsg_rtc_server_ept_cb,
|
|
rpmsg_destroy_ept) < 0)
|
|
{
|
|
kmm_free(client);
|
|
return;
|
|
}
|
|
|
|
if (server->lower->ops->rdtime(server->lower, &rtctime) >= 0)
|
|
{
|
|
msg.sec = timegm((FAR struct tm *)&rtctime);
|
|
msg.nsec = rtctime.tm_nsec;
|
|
msg.base_sec = g_basetime.tv_sec;
|
|
msg.base_nsec = g_basetime.tv_nsec;
|
|
|
|
msg.header.command = RPMSG_RTC_SYNC;
|
|
rpmsg_send(&client->ept, &msg, sizeof(msg));
|
|
}
|
|
|
|
nxmutex_lock(&server->lock);
|
|
list_add_tail(&server->list, &client->node);
|
|
nxmutex_unlock(&server->lock);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_rtc_initialize
|
|
*
|
|
* Description:
|
|
*
|
|
* Take remote core RTC as external RTC hardware through rpmsg.
|
|
*
|
|
* Returned Value:
|
|
* Return the lower half RTC driver instance on success;
|
|
* A NULL pointer on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_RTC_RPMSG_SERVER
|
|
FAR struct rtc_lowerhalf_s *rpmsg_rtc_initialize(void)
|
|
{
|
|
FAR struct rpmsg_rtc_lowerhalf_s *lower;
|
|
|
|
lower = kmm_zalloc(sizeof(*lower));
|
|
if (lower != NULL)
|
|
{
|
|
lower->ops = &g_rpmsg_rtc_ops;
|
|
|
|
rpmsg_register_callback(lower,
|
|
rpmsg_rtc_device_created,
|
|
rpmsg_rtc_device_destroy,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
return (FAR struct rtc_lowerhalf_s *)lower;
|
|
}
|
|
|
|
#else
|
|
/****************************************************************************
|
|
* Name: rpmsg_rtc_server_initialize
|
|
*
|
|
* Description:
|
|
* Sync RTC info to remote core without external RTC hardware through
|
|
* rpmsg.
|
|
*
|
|
* Returned Value:
|
|
* Return the lower half RTC driver instance on success;
|
|
* A NULL pointer on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
FAR struct rtc_lowerhalf_s *rpmsg_rtc_server_initialize(
|
|
FAR struct rtc_lowerhalf_s *lower)
|
|
{
|
|
FAR struct rpmsg_rtc_server_s *server;
|
|
|
|
server = kmm_zalloc(sizeof(*server));
|
|
if (server)
|
|
{
|
|
server->ops = &g_rpmsg_rtc_server_ops;
|
|
server->lower = lower;
|
|
list_initialize(&server->list);
|
|
nxmutex_init(&server->lock);
|
|
if (rpmsg_register_callback(server, NULL, NULL,
|
|
rpmsg_rtc_server_ns_match,
|
|
rpmsg_rtc_server_ns_bind) < 0)
|
|
{
|
|
nxmutex_destroy(&server->lock);
|
|
kmm_free(server);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return (FAR struct rtc_lowerhalf_s *)server;
|
|
}
|
|
#endif
|