Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Refactor example code #12

Merged
merged 10 commits into from
Jul 21, 2023
189 changes: 189 additions & 0 deletions examples/linux/common/common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// SPDX-License-Identifier: BSD-3-Clause

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <linux/rpmsg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include "common.h"

int app_rpmsg_create_ept(int rpfd, struct rpmsg_endpoint_info *eptinfo)
{
int ret;

ret = ioctl(rpfd, RPMSG_CREATE_EPT_IOCTL, eptinfo);
if (ret)
perror("Failed to create endpoint.\n");
return ret;
}

char *get_rpmsg_ept_dev_name(const char *rpmsg_char_name,
const char *ept_name,
char *ept_dev_name)
{
char sys_rpmsg_ept_name_path[64];
char svc_name[64];
char *sys_rpmsg_path = "/sys/class/rpmsg";
FILE *fp;
int i;
int ept_name_len;

for (i = 0; i < 128; i++) {
sprintf(sys_rpmsg_ept_name_path, "%s/%s/rpmsg%d/name",
sys_rpmsg_path, rpmsg_char_name, i);
printf("checking %s\n", sys_rpmsg_ept_name_path);
if (access(sys_rpmsg_ept_name_path, F_OK) < 0)
continue;
fp = fopen(sys_rpmsg_ept_name_path, "r");
if (!fp) {
printf("failed to open %s\n", sys_rpmsg_ept_name_path);
break;
}
fgets(svc_name, sizeof(svc_name), fp);
fclose(fp);
printf("svc_name: %s.\n",svc_name);
ept_name_len = strlen(ept_name);
if (ept_name_len > sizeof(svc_name))
ept_name_len = sizeof(svc_name);
if (!strncmp(svc_name, ept_name, ept_name_len)) {
sprintf(ept_dev_name, "rpmsg%d", i);
return ept_dev_name;
}
}

printf("Not able to RPMsg endpoint file for %s:%s.\n",
rpmsg_char_name, ept_name);
return NULL;
}

int bind_rpmsg_chrdev(const char *rpmsg_dev_name)
{
char fpath[256];
char *rpmsg_chdrv = "rpmsg_chrdev";
int fd;
int ret;

/* rpmsg dev overrides path */
sprintf(fpath, "%s/devices/%s/driver_override",
RPMSG_BUS_SYS, rpmsg_dev_name);
printf("open %s\n", fpath);
fd = open(fpath, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open %s, %s\n",
fpath, strerror(errno));
return -EINVAL;
}
ret = write(fd, rpmsg_chdrv, strlen(rpmsg_chdrv) + 1);
if (ret < 0) {
fprintf(stderr, "Failed to write %s to %s, %s\n",
rpmsg_chdrv, fpath, strerror(errno));
close(fd);
return -EINVAL;
glneo marked this conversation as resolved.
Show resolved Hide resolved
}
close(fd);

/* bind the rpmsg device to rpmsg char driver */
sprintf(fpath, "%s/drivers/%s/bind", RPMSG_BUS_SYS, rpmsg_chdrv);
fd = open(fpath, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open %s, %s\n",
fpath, strerror(errno));
return -EINVAL;
}
printf("write %s to %s\n", rpmsg_dev_name, fpath);
ret = write(fd, rpmsg_dev_name, strlen(rpmsg_dev_name) + 1);
if (ret < 0) {
fprintf(stderr, "Failed to write %s to %s, %s\n",
rpmsg_dev_name, fpath, strerror(errno));
close(fd);
return -EINVAL;
}
close(fd);
return 0;
}

int get_rpmsg_chrdev_fd(const char *rpmsg_dev_name, char *rpmsg_ctrl_name)
{
char dpath[2*NAME_MAX];
DIR *dir;
struct dirent *ent;
int fd;

sprintf(dpath, "%s/devices/%s/rpmsg", RPMSG_BUS_SYS, rpmsg_dev_name);
printf("opendir %s\n", dpath);
dir = opendir(dpath);
if (dir == NULL) {
fprintf(stderr, "opendir %s, %s\n", dpath, strerror(errno));
return -EINVAL;
}
while ((ent = readdir(dir)) != NULL) {
if (!strncmp(ent->d_name, "rpmsg_ctrl", 10)) {
sprintf(dpath, "/dev/%s", ent->d_name);
closedir(dir);
printf("open %s\n", dpath);
fd = open(dpath, O_RDWR | O_NONBLOCK);
if (fd < 0) {
fprintf(stderr, "open %s, %s\n",
dpath, strerror(errno));
return fd;
arnopo marked this conversation as resolved.
Show resolved Hide resolved
}
sprintf(rpmsg_ctrl_name, "%s", ent->d_name);
return fd;
}
}

fprintf(stderr, "No rpmsg_ctrl file found in %s\n", dpath);
closedir(dir);
return -EINVAL;
}

static void set_src_dst(char *out, struct rpmsg_endpoint_info *pep)
{
long dst = 0;
char *lastdot = strrchr(out, '.');

if (lastdot == NULL)
return;
dst = strtol(lastdot + 1, NULL, 10);
if ((errno == ERANGE && (dst == LONG_MAX || dst == LONG_MIN))
|| (errno != 0 && dst == 0)) {
return;
}
pep->dst = (unsigned int)dst;
}

/*
* return the first dirent matching rpmsg-openamp-demo-channel
* in /sys/bus/rpmsg/devices/ E.g.:
* virtio0.rpmsg-openamp-demo-channel.-1.1024
*/
int lookup_channel(char *out, struct rpmsg_endpoint_info *pep)
{
char dpath[] = RPMSG_BUS_SYS "/devices";
struct dirent *ent;
DIR *dir = opendir(dpath);

if (dir == NULL) {
fprintf(stderr, "opendir %s, %s\n", dpath, strerror(errno));
return -EINVAL;
}
while ((ent = readdir(dir)) != NULL) {
if (strstr(ent->d_name, pep->name)) {
strncpy(out, ent->d_name, NAME_MAX);
set_src_dst(out, pep);
printf("using dev file: %s\n", out);
closedir(dir);
return 0;
}
}
closedir(dir);
fprintf(stderr, "No dev file for %s in %s\n", pep->name, dpath);
return -EINVAL;
}
18 changes: 18 additions & 0 deletions examples/linux/common/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: BSD-3-Clause

#ifndef __COMMON__H__
#define __COMMON__H__

#include <linux/rpmsg.h>

#define RPMSG_BUS_SYS "/sys/bus/rpmsg"

int app_rpmsg_create_ept(int rpfd, struct rpmsg_endpoint_info *eptinfo);
char *get_rpmsg_ept_dev_name(const char *rpmsg_char_name,
const char *ept_name,
char *ept_dev_name);
int bind_rpmsg_chrdev(const char *rpmsg_dev_name);
int get_rpmsg_chrdev_fd(const char *rpmsg_dev_name, char *rpmsg_ctrl_name);
int lookup_channel(char *out, struct rpmsg_endpoint_info *pep);

#endif /* __COMMON__H__ */
4 changes: 2 additions & 2 deletions examples/linux/rpmsg-echo-test/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

APP = echo_test
APP_OBJS = echo_test.o
APP_OBJS = echo_test.o ../common/common.o
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patch.

We should include common.o in clean target as well.
So when we do make clean, it re-builds common.o as well.
or probably introduce new target (distclean), that will remove common.o as well. clean will only remove local directory *.o and distclean will remove all dependencies as well such as common.o. I am fine with either approach.

Thanks.

Copy link
Contributor Author

@glneo glneo Jul 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how the 'clean' option would interact when one wanted only to clean the current project but I'd assume that would be rare anyway. Easy enough to just use APP_OBJS as the rm targets.

Fixing out of tree builds (or using CMake or similar) would fix all that, but that would be a task for another day :)


# Add any other object files to this list below

Expand All @@ -11,7 +11,7 @@ $(APP): $(APP_OBJS)
$(CC) $(LDFLAGS) -o $@ $(APP_OBJS) $(LDLIBS)

clean:
rm -rf $(APP) *.o
rm -rf $(APP) $(APP_OBJS)

%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
Expand Down
Loading