mirror of
https://github.com/apache/nuttx.git
synced 2026-05-21 04:52:02 +08:00
drivers/net/rpmsgdrv.c: add bidirectional data netdev support, clien side
It's the first simple version of rpmsg-net, include: - Transfer command with data copy (maybe optimize later), no need to ack - Control command with ack, but only ifup/ifdown no need to ack - Client side: Another module can call `net_rpmsg_drv_alloc` to create netdev and register it. Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
+215
-53
@@ -71,9 +71,14 @@ struct net_rpmsg_drv_cookie_s
|
||||
|
||||
struct net_rpmsg_drv_s
|
||||
{
|
||||
FAR const char *cpuname;
|
||||
FAR const char *devname;
|
||||
char cpuname[RPMSG_NAME_SIZE];
|
||||
netpkt_queue_t rxqueue; /* RX packet queue */
|
||||
FAR void *priv; /* Private data for upper layer */
|
||||
net_rpmsg_drv_cb_t cb; /* IFUP/DOWN Callback function */
|
||||
sem_t wait; /* Wait sem, used for preventing any
|
||||
* operation until the connection
|
||||
* between two cpu established.
|
||||
*/
|
||||
struct rpmsg_endpoint ept;
|
||||
|
||||
/* This holds the information visible to the NuttX network */
|
||||
@@ -92,6 +97,12 @@ struct net_rpmsg_drv_s
|
||||
static int net_rpmsg_drv_default_handler(FAR struct rpmsg_endpoint *ept,
|
||||
FAR void *data, size_t len,
|
||||
uint32_t src, FAR void *priv);
|
||||
static int net_rpmsg_drv_ifup_handler(FAR struct rpmsg_endpoint *ept,
|
||||
FAR void *data, size_t len,
|
||||
uint32_t src, FAR void *priv);
|
||||
static int net_rpmsg_drv_ifdown_handler(FAR struct rpmsg_endpoint *ept,
|
||||
FAR void *data, size_t len,
|
||||
uint32_t src, FAR void *priv);
|
||||
static int net_rpmsg_drv_sockioctl_handler(FAR struct rpmsg_endpoint *ept,
|
||||
FAR void *data, size_t len,
|
||||
uint32_t src, FAR void *priv);
|
||||
@@ -147,8 +158,8 @@ static int net_rpmsg_drv_ioctl(FAR struct netdev_lowerhalf_s *dev, int cmd,
|
||||
|
||||
static const rpmsg_ept_cb g_net_rpmsg_drv_handler[] =
|
||||
{
|
||||
[NET_RPMSG_IFUP] = net_rpmsg_drv_default_handler,
|
||||
[NET_RPMSG_IFDOWN] = net_rpmsg_drv_default_handler,
|
||||
[NET_RPMSG_IFUP] = net_rpmsg_drv_ifup_handler,
|
||||
[NET_RPMSG_IFDOWN] = net_rpmsg_drv_ifdown_handler,
|
||||
[NET_RPMSG_ADDMCAST] = net_rpmsg_drv_default_handler,
|
||||
[NET_RPMSG_RMMCAST] = net_rpmsg_drv_default_handler,
|
||||
[NET_RPMSG_DEVIOCTL] = net_rpmsg_drv_default_handler,
|
||||
@@ -281,6 +292,42 @@ static int net_rpmsg_drv_default_handler(FAR struct rpmsg_endpoint *ept,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_rpmsg_drv_ifup_handler(FAR struct rpmsg_endpoint *ept,
|
||||
FAR void *data, size_t len,
|
||||
uint32_t src, FAR void *priv_)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv = priv_;
|
||||
FAR struct net_rpmsg_header_s *header = data;
|
||||
|
||||
netdev_lower_carrier_on(&priv->dev);
|
||||
if (priv->cb != NULL)
|
||||
{
|
||||
priv->cb(&priv->dev, NET_RPMSG_EVENT_CARRIER_ON);
|
||||
}
|
||||
|
||||
rpmsg_send_response(ept, header, sizeof(*header), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_rpmsg_drv_ifdown_handler(FAR struct rpmsg_endpoint *ept,
|
||||
FAR void *data, size_t len,
|
||||
uint32_t src, FAR void *priv_)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv = priv_;
|
||||
FAR struct net_rpmsg_header_s *header = data;
|
||||
|
||||
netdev_lower_carrier_off(&priv->dev);
|
||||
if (priv->cb != NULL)
|
||||
{
|
||||
priv->cb(&priv->dev, NET_RPMSG_EVENT_CARRIER_OFF);
|
||||
}
|
||||
|
||||
rpmsg_send_response(ept, header, sizeof(*header), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_rpmsg_drv_sockioctl_task(int argc, FAR char *argv[])
|
||||
{
|
||||
FAR struct net_rpmsg_ioctl_s *msg;
|
||||
@@ -438,6 +485,44 @@ static int net_rpmsg_drv_default_response(FAR struct rpmsg_endpoint *ept,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_ept_release
|
||||
****************************************************************************/
|
||||
|
||||
static void net_rpmsg_drv_ept_release(FAR struct rpmsg_endpoint *ept)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv = ept->priv;
|
||||
|
||||
netdev_lower_carrier_off(&priv->dev);
|
||||
rpmsg_wait(&priv->ept, &priv->wait);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_ns_bound
|
||||
*
|
||||
* Description:
|
||||
* Rpmsg device end point service bound callback function , called when
|
||||
* remote end point address is received.
|
||||
*
|
||||
* Parameters:
|
||||
* ept - The rpmsg-device end point
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void net_rpmsg_drv_ns_bound(FAR struct rpmsg_endpoint *ept)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv = ept->priv;
|
||||
|
||||
rpmsg_post(&priv->ept, &priv->wait);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_device_created
|
||||
****************************************************************************/
|
||||
|
||||
static void net_rpmsg_drv_device_created(FAR struct rpmsg_device *rdev,
|
||||
FAR void *priv_)
|
||||
{
|
||||
@@ -448,7 +533,7 @@ static void net_rpmsg_drv_device_created(FAR struct rpmsg_device *rdev,
|
||||
{
|
||||
priv->ept.priv = priv;
|
||||
snprintf(eptname, sizeof(eptname),
|
||||
NET_RPMSG_EPT_NAME, priv->devname);
|
||||
NET_RPMSG_EPT_PREFIX "%s", priv->dev.netdev.d_ifname);
|
||||
|
||||
rpmsg_create_ept(&priv->ept, rdev, eptname,
|
||||
RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
|
||||
@@ -456,6 +541,10 @@ static void net_rpmsg_drv_device_created(FAR struct rpmsg_device *rdev,
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_device_destroy
|
||||
****************************************************************************/
|
||||
|
||||
static void net_rpmsg_drv_device_destroy(FAR struct rpmsg_device *rdev,
|
||||
FAR void *priv_)
|
||||
{
|
||||
@@ -496,8 +585,16 @@ static int net_rpmsg_drv_send_recv(FAR struct netdev_lowerhalf_s *dev,
|
||||
container_of(dev, struct net_rpmsg_drv_s, dev);
|
||||
FAR struct net_rpmsg_header_s *header = header_;
|
||||
FAR struct net_rpmsg_drv_cookie_s cookie;
|
||||
int sval = 0;
|
||||
int ret;
|
||||
|
||||
nxsem_get_value(&priv->wait, &sval);
|
||||
if (sval <= 0)
|
||||
{
|
||||
rpmsg_wait(&priv->ept, &priv->wait);
|
||||
rpmsg_post(&priv->ept, &priv->wait);
|
||||
}
|
||||
|
||||
nxsem_init(&cookie.sem, 0, 0);
|
||||
|
||||
cookie.header = header;
|
||||
@@ -540,6 +637,8 @@ out:
|
||||
|
||||
static int net_rpmsg_drv_ifup(FAR struct netdev_lowerhalf_s *dev)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv =
|
||||
container_of(dev, struct net_rpmsg_drv_s, dev);
|
||||
struct net_rpmsg_ifup_s msg =
|
||||
{
|
||||
};
|
||||
@@ -639,6 +738,11 @@ static int net_rpmsg_drv_ifup(FAR struct netdev_lowerhalf_s *dev)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (priv->cb != NULL)
|
||||
{
|
||||
priv->cb(dev, NET_RPMSG_EVENT_IF_UP);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -661,14 +765,26 @@ static int net_rpmsg_drv_ifup(FAR struct netdev_lowerhalf_s *dev)
|
||||
|
||||
static int net_rpmsg_drv_ifdown(FAR struct netdev_lowerhalf_s *dev)
|
||||
{
|
||||
FAR struct net_rpmsg_ifdown_s msg;
|
||||
FAR struct net_rpmsg_drv_s *priv =
|
||||
container_of(dev, struct net_rpmsg_drv_s, dev);
|
||||
struct net_rpmsg_ifdown_s msg =
|
||||
{
|
||||
};
|
||||
|
||||
/* Put the EMAC in its reset, non-operational state. This should be
|
||||
* a known configuration that will guarantee the net_rpmsg_drv_ifup()
|
||||
* always successfully brings the interface back up.
|
||||
*/
|
||||
int ret;
|
||||
|
||||
return net_rpmsg_drv_send_recv(dev, &msg, NET_RPMSG_IFDOWN, sizeof(msg));
|
||||
ret = net_rpmsg_drv_send_recv(dev, &msg, NET_RPMSG_IFDOWN, sizeof(msg));
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->cb != NULL)
|
||||
{
|
||||
priv->cb(dev, NET_RPMSG_EVENT_IF_DOWN);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -783,6 +899,45 @@ static int net_rpmsg_drv_ioctl(FAR struct netdev_lowerhalf_s *dev, int cmd,
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_alloc
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct net_rpmsg_drv_s *
|
||||
net_rpmsg_drv_alloc(FAR const char *devname, enum net_lltype_e lltype)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv = kmm_zalloc(sizeof(*priv));
|
||||
FAR struct netdev_lowerhalf_s *netdev;
|
||||
|
||||
if (!priv)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
netdev = &priv->dev;
|
||||
netdev->quota[NETPKT_RX] = CONFIG_IOB_NBUFFERS /
|
||||
NET_RPMSG_DRV_MAX_NIOB / 4;
|
||||
netdev->quota[NETPKT_TX] = 1;
|
||||
netdev->ops = &g_net_rpmsg_drv_ops;
|
||||
|
||||
priv->ept.priv = priv;
|
||||
priv->ept.release_cb = net_rpmsg_drv_ept_release;
|
||||
priv->ept.ns_bound_cb = net_rpmsg_drv_ns_bound;
|
||||
|
||||
nxsem_init(&priv->wait, 0, 0);
|
||||
|
||||
/* Init a random MAC address, the caller can override it. */
|
||||
|
||||
arc4random_buf(&netdev->netdev.d_mac.ether.ether_addr_octet,
|
||||
sizeof(netdev->netdev.d_mac.ether.ether_addr_octet));
|
||||
|
||||
strlcpy(netdev->netdev.d_ifname, devname, IFNAMSIZ);
|
||||
|
||||
netdev_lower_register(netdev, lltype);
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@@ -791,52 +946,44 @@ static int net_rpmsg_drv_ioctl(FAR struct netdev_lowerhalf_s *dev, int cmd,
|
||||
* Name: net_rpmsg_drv_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize the net rpmsg driver
|
||||
* Allocate a new network device instance for the RPMSG network and
|
||||
* register it with the network device manager. This is the client side of
|
||||
* the RPMSG driver. The RPMSG driver is the server side of the driver.
|
||||
*
|
||||
* Parameters:
|
||||
* name - Specify the netdev name
|
||||
* lltype - Identify the link type
|
||||
* cpuname - Remote CPU name
|
||||
* devname - Local and remote network device name
|
||||
* lltype - Link layer type
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; Negated errno on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called early in initialization before multi-tasking is initiated.
|
||||
* A pointer to the allocated network device instance. NULL is returned on
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int net_rpmsg_drv_init(FAR const char *cpuname,
|
||||
FAR const char *devname,
|
||||
enum net_lltype_e lltype)
|
||||
FAR struct netdev_lowerhalf_s *
|
||||
net_rpmsg_drv_init(FAR const char *cpuname, FAR const char *devname,
|
||||
enum net_lltype_e lltype)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv;
|
||||
FAR struct net_rpmsg_drv_s *drv;
|
||||
FAR struct netdev_lowerhalf_s *dev;
|
||||
int ret;
|
||||
|
||||
/* Allocate the interface structure */
|
||||
|
||||
priv = kmm_zalloc(sizeof(*priv));
|
||||
if (priv == NULL)
|
||||
if (!devname || !cpuname ||
|
||||
!(drv = net_rpmsg_drv_alloc(devname, lltype)))
|
||||
{
|
||||
return -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = &priv->dev;
|
||||
strlcpy(drv->cpuname, cpuname, RPMSG_NAME_SIZE);
|
||||
|
||||
priv->cpuname = cpuname;
|
||||
priv->devname = devname;
|
||||
|
||||
/* Initialize the driver structure */
|
||||
|
||||
strlcpy(dev->netdev.d_ifname, devname, IFNAMSIZ);
|
||||
|
||||
dev->quota[NETPKT_RX] = CONFIG_IOB_NBUFFERS / NET_RPMSG_DRV_MAX_NIOB / 4;
|
||||
dev->quota[NETPKT_TX] = 1;
|
||||
dev->ops = &g_net_rpmsg_drv_ops;
|
||||
dev = &drv->dev;
|
||||
|
||||
/* Register the device with the openamp */
|
||||
|
||||
ret = rpmsg_register_callback(priv,
|
||||
ret = rpmsg_register_callback(drv,
|
||||
net_rpmsg_drv_device_created,
|
||||
net_rpmsg_drv_device_destroy,
|
||||
NULL,
|
||||
@@ -844,22 +991,37 @@ int net_rpmsg_drv_init(FAR const char *cpuname,
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
netdev_lower_unregister(dev);
|
||||
nxsem_destroy(&drv->wait);
|
||||
kmm_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Register the device with the OS so that socket IOCTLs can be performed */
|
||||
|
||||
ret = netdev_lower_register(dev, lltype);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsg_unregister_callback(dev,
|
||||
net_rpmsg_drv_device_created,
|
||||
net_rpmsg_drv_device_destroy,
|
||||
NULL,
|
||||
NULL);
|
||||
kmm_free(priv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return dev;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_priv
|
||||
****************************************************************************/
|
||||
|
||||
FAR void *net_rpmsg_drv_priv(FAR struct netdev_lowerhalf_s *dev)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv =
|
||||
container_of(dev, struct net_rpmsg_drv_s, dev);
|
||||
|
||||
return priv->priv;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_set_callback
|
||||
****************************************************************************/
|
||||
|
||||
void net_rpmsg_drv_set_callback(FAR struct netdev_lowerhalf_s *dev,
|
||||
net_rpmsg_drv_cb_t cb, FAR void *priv)
|
||||
{
|
||||
FAR struct net_rpmsg_drv_s *priv =
|
||||
container_of(dev, struct net_rpmsg_drv_s, dev);
|
||||
|
||||
priv->cb = cb;
|
||||
priv->priv = priv;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define NET_RPMSG_EPT_NAME "rpmsg-%s"
|
||||
#define NET_RPMSG_EPT_PREFIX "rpmsg-net-"
|
||||
|
||||
#define NET_RPMSG_IFUP 0 /* IP-->LINK */
|
||||
#define NET_RPMSG_IFDOWN 1 /* IP-->LINK */
|
||||
|
||||
@@ -28,18 +28,94 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev_lowerhalf.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_RPMSG_DRV
|
||||
|
||||
#define NET_RPMSG_EVENT_IF_UP 1
|
||||
#define NET_RPMSG_EVENT_IF_DOWN 2
|
||||
#define NET_RPMSG_EVENT_CARRIER_ON 3
|
||||
#define NET_RPMSG_EVENT_CARRIER_OFF 4
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
typedef CODE void (*net_rpmsg_drv_cb_t)(FAR struct netdev_lowerhalf_s *dev,
|
||||
int event);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_RPMSG_DRV
|
||||
int net_rpmsg_drv_init(FAR const char *cpuname,
|
||||
FAR const char *devname,
|
||||
enum net_lltype_e lltype);
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define net_rpmsg_drv_init(cpuname, devname, lltye)
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_init
|
||||
*
|
||||
* Description:
|
||||
* Allocate a new network device instance for the RPMSG network and
|
||||
* register it with the network device manager. This is the client side of
|
||||
* the RPMSG driver. The RPMSG driver is the server side of the driver.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpuname - Remote CPU name
|
||||
* devname - Local and remote network device name
|
||||
* lltype - Link layer type
|
||||
* priv - Reference to the caller's private data
|
||||
*
|
||||
* Returned Value:
|
||||
* A pointer to the allocated network device instance. NULL is returned on
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct netdev_lowerhalf_s *
|
||||
net_rpmsg_drv_init(FAR const char *cpuname, FAR const char *devname,
|
||||
enum net_lltype_e lltype);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_priv
|
||||
*
|
||||
* Description:
|
||||
* Get the private data associated with the network device instance.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Reference to the network device instance.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR void *net_rpmsg_drv_priv(FAR struct netdev_lowerhalf_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_rpmsg_drv_set_callback
|
||||
*
|
||||
* Description:
|
||||
* Set the callback function for the network device instance.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Reference to the network device instance.
|
||||
* cb - Callback function to be set.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void net_rpmsg_drv_set_callback(FAR struct netdev_lowerhalf_s *dev,
|
||||
net_rpmsg_drv_cb_t cb, FAR void *priv);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* __INCLUDE_NUTTX_NET_RPMSGDRV_H */
|
||||
|
||||
Reference in New Issue
Block a user