--- /dev/null
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file trinity-cuse-triv2.cc
+ * @date 12 Apr 2021
+ * @brief Implementation of triv2 ioctl() in the cuse driver
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <triv2profile.h>
+#include <ne-conf.h>
+
+#include "trinity-cuse.h"
+
+/**
+ * @brief TRIV2 impl. of get_version ioctl()
+ */
+static int
+triv2_get_version (uint32_t *version)
+{
+ *version = trinity_gen_ver (2, 2, 0, 0);
+ fprintf (stderr, "version: %x\n", *version);
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_api_level ioctl()
+ */
+static int
+triv2_get_api_level (uint32_t *api_level)
+{
+ *api_level = TRINITY_API_LEVEL;
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_state ioctl()
+ */
+static int
+triv2_get_state (uint32_t *state)
+{
+ *state = STATE_READY;
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_tops ioctl()
+ */
+static int
+triv2_get_tops (uint32_t *tops)
+{
+ *tops = 2;
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_dspm ioctl()
+ */
+static int
+triv2_get_dspm (uint32_t *dspm)
+{
+ *dspm = UINT32_MAX;
+ return 0;
+}
+
+/** @brief The ioctl vtable for TRIV2 devices */
+static trinity_cuse_ioctl_vtable triv2_vtable {
+ .get_version = triv2_get_version,
+ .get_api_level = triv2_get_api_level,
+ .get_state = triv2_get_state,
+ .get_tops = triv2_get_tops,
+ .get_dspm = triv2_get_dspm,
+ /* NYI */
+};
+
+/** @brief Setting the ioctl vtable */
+bool
+set_ioctl_vtable_triv2 (trinity_cuse_ioctl_vtable ** vtable) {
+ if (vtable == nullptr)
+ return false;
+
+ *vtable = &triv2_vtable;
+ return true;
+}
--- /dev/null
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file trinity-cuse.cc
+ * @date 12 Apr 2021
+ * @brief Utility to provide virtual device nodes of trinity devices
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#define FUSE_USE_VERSION 29
+
+#include <iostream>
+
+#include <cuse_lowlevel.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+
+#include "trinity-cuse.h"
+
+static trinity_cuse_ioctl_vtable *vtable;
+
+extern bool set_ioctl_vtable_triv2 (trinity_cuse_ioctl_vtable **);
+
+/**
+ * @brief Find the ioctl vtable for the given device type
+ */
+bool
+find_ioctl_vtable (const std::string &dev_name)
+{
+ if (dev_name == "triv2")
+ return set_ioctl_vtable_triv2 (&vtable);
+
+ return false;
+}
+
+/**
+ * @brief impl. of .open ()
+ */
+static void
+trinity_cuse_open (fuse_req_t req, struct fuse_file_info *fi)
+{
+ trinity_cuse_context *ctx;
+
+ ctx = (trinity_cuse_context *) malloc (sizeof (*ctx));
+ if (ctx == NULL) {
+ fuse_reply_err (req, ENOMEM);
+ return;
+ }
+
+ std::cerr << "open!!\n";
+
+ fi->fh = (uint64_t) ctx;
+ fuse_reply_open(req, fi);
+}
+
+/**
+ * @brief impl. of .release ()
+ */
+static void
+trinity_cuse_release (fuse_req_t req, struct fuse_file_info *fi)
+{
+ trinity_cuse_context *ctx = (trinity_cuse_context *) fi->fh;
+
+ if (ctx)
+ free (ctx);
+
+ fi->fh = 0;
+ fuse_reply_err (req, 0);
+}
+
+/**
+ * @brief impl. of .ioctl ()
+ */
+static void
+trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg,
+ struct fuse_file_info *fi, unsigned int flags,
+ const void *in_buf, size_t in_size, size_t out_size)
+{
+ (void) fi;
+
+ if (flags & FUSE_IOCTL_COMPAT) {
+ fuse_reply_err (req, ENOSYS);
+ return;
+ }
+
+ if (vtable == nullptr) {
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ switch (cmd) {
+ case TRINITY_IOCTL_GET_VERSION:
+ if (!out_size) {
+ struct iovec iov = { arg, sizeof (uint32_t) };
+ fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+ } else {
+ uint32_t val;
+ vtable->get_version (&val);
+ fuse_reply_ioctl (req, 0, &val, sizeof (val));
+ }
+ break;
+ case TRINITY_IOCTL_GET_API_LEVEL:
+ if (!out_size) {
+ struct iovec iov = { arg, sizeof (uint32_t) };
+ fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+ } else {
+ uint32_t val;
+ vtable->get_api_level (&val);
+ fuse_reply_ioctl (req, 0, &val, sizeof (val));
+ }
+ break;
+ case TRINITY_IOCTL_GET_STATE:
+ if (!out_size) {
+ struct iovec iov = { arg, sizeof (uint32_t) };
+ fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+ } else {
+ uint32_t val;
+ vtable->get_state (&val);
+ fuse_reply_ioctl (req, 0, &val, sizeof (val));
+ }
+ break;
+ case TRINITY_IOCTL_GET_TOPS:
+ if (!out_size) {
+ struct iovec iov = { arg, sizeof (uint32_t) };
+ fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+ } else {
+ uint32_t val;
+ vtable->get_tops (&val);
+ fuse_reply_ioctl (req, 0, &val, sizeof (val));
+ }
+ break;
+ case TRINITY_IOCTL_GET_DSPM:
+ if (!out_size) {
+ struct iovec iov = { arg, sizeof (uint32_t) };
+ fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+ } else {
+ uint32_t val;
+ vtable->get_dspm (&val);
+ fuse_reply_ioctl (req, 0, &val, sizeof (val));
+ }
+ break;
+ /* NYI */
+ default:
+ fuse_reply_err (req, ENOTTY);
+ break;
+ }
+
+ fuse_reply_err (req, 0);
+}
+
+/** @brief Structure to describe parameters */
+struct trinity_cuse_param {
+ unsigned int major;
+ unsigned int minor;
+ std::string dev_name;
+ bool is_help;
+};
+
+#define TRINITY_OPT(t, p) { t, offsetof (struct trinity_cuse_param, p), 1 }
+
+enum {
+ KEY_HELP
+};
+
+/** @brief The definitions of available options */
+static const struct fuse_opt trinity_cuse_opts[] = {
+ TRINITY_OPT("-M %u", major),
+ TRINITY_OPT("--maj=%u", major),
+ TRINITY_OPT("-m %u", minor),
+ TRINITY_OPT("--min=%u", minor),
+ FUSE_OPT_KEY("-h", KEY_HELP),
+ FUSE_OPT_KEY("--help", KEY_HELP),
+ FUSE_OPT_END
+};
+
+/** @brief Print the help message */
+static void
+print_help_message ()
+{
+ static const char *usage =
+ "\nUsage: trinity-cuse [options] [device name]\n"
+ "options:\n"
+ " --maj=MAJ|-M MAJ device major number\n"
+ " --min=MIN|-m MIN device minor number\n"
+ " --help|-h print this help message\n";
+
+ std::cerr << usage;
+}
+
+/** @brief Parse the given arguments */
+static int
+trinity_cuse_parse_args(void *data, const char *arg, int key,
+ struct fuse_args *outargs)
+{
+ struct trinity_cuse_param *param = (struct trinity_cuse_param *) data;
+
+ (void)outargs;
+ (void)arg;
+
+ switch (key) {
+ case FUSE_OPT_KEY_NONOPT:
+ param->dev_name = std::string (arg);
+ return 0;
+ case KEY_HELP:
+ param->is_help = true;
+ print_help_message ();
+ return fuse_opt_add_arg (outargs, "-ho");
+ default:
+ return 1;
+ }
+}
+
+/** @brief trinity cuse driver's lowlevel ops */
+static const struct cuse_lowlevel_ops trinity_cuse_clop = {
+ .init = nullptr,
+ .init_done = nullptr,
+ .destroy = nullptr,
+ .open = trinity_cuse_open,
+ .read = nullptr,
+ .write = nullptr,
+ .flush = nullptr,
+ .release = trinity_cuse_release,
+ .fsync = nullptr,
+ .ioctl = trinity_cuse_ioctl,
+ .poll = nullptr
+};
+
+/**
+ * @brief main routine of trinity-cuse
+ */
+int
+main (int argc, char **argv)
+{
+ struct fuse_args args = FUSE_ARGS_INIT (argc, argv);
+ struct trinity_cuse_param param = { 0 };
+ struct cuse_info ci = { 0 };
+ std::string dev_name ("DEVNAME=");
+
+ if (fuse_opt_parse (&args, ¶m, trinity_cuse_opts, trinity_cuse_parse_args)) {
+ std::cerr << "[Error] Failed to parse options\n";
+ return -EINVAL;
+ }
+
+ if (param.is_help == 1)
+ return 0;
+
+ if (param.dev_name.empty ()) {
+ std::cerr << "[Error] Missing device name (e.g., --name=triv2)\n";
+ print_help_message ();
+ return -EINVAL;
+ }
+
+ if (!find_ioctl_vtable (param.dev_name)) {
+ std::cerr << "[Error] Unsupported device: " << param.dev_name << "\n";
+ print_help_message ();
+ return -ENOENT;
+ }
+
+ dev_name += param.dev_name;
+ dev_name += "-0";
+ const char *dev_info_argv[] = { dev_name.c_str() };
+
+ ci.dev_major = param.major;
+ ci.dev_minor = param.minor;
+ ci.dev_info_argc = 1;
+ ci.dev_info_argv = dev_info_argv;
+ ci.flags = CUSE_UNRESTRICTED_IOCTL;
+
+ return cuse_lowlevel_main (args.argc, args.argv, &ci, &trinity_cuse_clop, NULL);
+}