interface: Add support for multiple transfer interfaces 35/223035/9
authorDongwoo Lee <dwoo08.lee@samsung.com>
Tue, 17 Mar 2020 04:36:02 +0000 (13:36 +0900)
committerDongwoo Lee <dwoo08.lee@samsung.com>
Wed, 18 Mar 2020 08:32:46 +0000 (17:32 +0900)
To support USB connection, multiple interface f/w should be required
before. This adds only interface f/w, so network connection is
still processed without f/w.

Change-Id: I367f9e961daefe3b9005104084955edbe0851057
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
CMakeLists.txt
src/interface.c [new file with mode: 0644]
src/interface.h [new file with mode: 0644]

index c722f06..9fcc572 100644 (file)
@@ -6,7 +6,7 @@ SET(CMAKE_EXE_LINKER_FLAGS "-pie")
 
 FIND_PACKAGE(Threads REQUIRED)
 
-ADD_EXECUTABLE(${PROJECT_NAME} src/main.c src/thor.c src/dfu.c src/net.c)
+ADD_EXECUTABLE(${PROJECT_NAME} src/main.c src/thor.c src/dfu.c src/interface.c src/net.c)
 
 INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src)
 
diff --git a/src/interface.c b/src/interface.c
new file mode 100644 (file)
index 0000000..de6f559
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * flash-manager - Tizen kernel-level image flashing solution
+ *
+ * Licensed 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/queue.h>
+
+#include "tfm.h"
+#include "interface.h"
+
+struct tfm_interface_context {
+       struct tfm_interface *connected;
+
+       pthread_mutex_t mutex;
+       pthread_cond_t signal;
+
+       LIST_HEAD(intflist, tfm_interface) interface_list;
+};
+
+INTERFACE interface_avail_list = LIST_HEAD_INITIALIZER(interface_avail_list);
+
+ssize_t tfm_interface_send(struct tfm_interface *intf, void *buf, ssize_t len)
+{
+       if (!intf)
+               return -EINVAL;
+
+       if (intf->ops && intf->ops->tx_data)
+               return intf->ops->tx_data(intf->txd, buf, len);
+
+       return -ENOENT;
+}
+
+ssize_t tfm_interface_recv(struct tfm_interface *intf, void *buf, ssize_t len)
+{
+       if (!intf)
+               return -EINVAL;
+
+       if (intf->ops && intf->ops->rx_data)
+               return intf->ops->rx_data(intf->rxd, buf, len);
+
+       return -ENOENT;
+}
+
+int tfm_interface_set_private(struct tfm_interface_context *ictx,
+                                       char *name, void *data)
+{
+       struct tfm_interface *intf = NULL;
+
+       LIST_FOREACH(intf, &ictx->interface_list, entry) {
+               if (!strncmp(intf->name, name, strlen(name)))
+                       break;
+       }
+
+       if (!intf) {
+               fprintf(stderr, "cannot find interface: %s\n", name);
+               return -ENOENT;
+       }
+
+       intf->priv = data;
+
+       return 0;
+}
+
+static void *connect_thread_main(void *ptr)
+{
+       struct tfm_interface *intf = ptr;
+       struct tfm_interface_context *ictx = intf->ctx;
+       int ret;
+
+       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+       /* for checking which interface is connected */
+       intf->tid = pthread_self();
+
+       if (!intf->ops || !intf->ops->connect || !intf->ops->disconnect)
+               return NULL;
+
+       ret = intf->ops->connect(intf);
+       if (ret < 0) {
+               fprintf(stderr, "failed to connect: %s\n", intf->name);
+               return NULL;
+       }
+
+       pthread_mutex_lock(&ictx->mutex);
+       if (ictx->connected) {
+               pthread_mutex_unlock(&ictx->mutex);
+               fprintf(stderr,
+                       "interface %s will be ignored due to %s\n",
+                       intf->name, ictx->connected->name);
+               intf->ops->disconnect(intf);
+               return NULL;
+       }
+
+       ictx->connected = intf;
+       pthread_mutex_unlock(&ictx->mutex);
+
+       fprintf(stdout, "interface %s is connected.\n", intf->name);
+
+       pthread_cond_signal(&ictx->signal);
+
+       return NULL;
+}
+
+struct tfm_interface *tfm_interface_connect(struct tfm_interface_context *ictx)
+{
+       struct tfm_interface *intf;
+
+       LIST_FOREACH(intf, &ictx->interface_list, entry) {
+               pthread_t t;
+
+               pthread_create(&t, NULL, connect_thread_main, (void *)intf);
+               pthread_detach(t);
+       }
+
+       pthread_mutex_lock(&ictx->mutex);
+       while (!ictx->connected)
+               pthread_cond_wait(&ictx->signal, &ictx->mutex);
+       pthread_mutex_unlock(&ictx->mutex);
+
+       LIST_FOREACH(intf, &ictx->interface_list, entry) {
+               /* Terminate threads waiting for other connection */
+               if (intf != ictx->connected) {
+                       intf->ctx = NULL;
+                       pthread_cancel(intf->tid);
+               }
+       }
+
+       return ictx->connected;
+}
+
+void tfm_interface_disconnect(struct tfm_interface *intf)
+{
+       if (!intf)
+               return;
+
+       if (intf->ops && intf->ops->disconnect)
+               intf->ops->disconnect(intf);
+
+       intf->ctx->connected = NULL;
+}
+
+static void destroy_interface_list(struct tfm_interface_context *ictx)
+{
+       struct tfm_interface *intf, *temp;
+
+       intf = LIST_FIRST(&ictx->interface_list);
+       while (intf != NULL) {
+               temp = intf;
+               intf = LIST_NEXT(intf, entry);
+
+               LIST_REMOVE(temp, entry);
+               free(temp);
+       }
+}
+
+struct tfm_interface_context *tfm_interface_init(void)
+{
+       struct tfm_interface_context *ictx;
+       struct tfm_interface_driver *driver;
+
+       ictx = (struct tfm_interface_context *)malloc(sizeof(*ictx));
+       if (!ictx)
+               return NULL;
+
+       ictx->connected = NULL;
+
+       pthread_mutex_init(&ictx->mutex, NULL);
+       pthread_cond_init(&ictx->signal, NULL);
+
+       LIST_INIT(&ictx->interface_list);
+
+       LIST_FOREACH(driver, &interface_avail_list, entry) {
+               struct tfm_interface *intf;
+
+               intf = (struct tfm_interface *)malloc(sizeof(*intf));
+               if (!intf)
+                       goto err;
+
+               intf->name = driver->name;
+               intf->rxd = intf->txd = -1;
+               intf->ops = &driver->ops;
+               intf->priv = NULL;
+               intf->tid = 0;
+               intf->ctx = ictx;
+
+               LIST_INSERT_HEAD(&ictx->interface_list, intf, entry);
+       }
+
+       return ictx;
+
+err:
+       destroy_interface_list(ictx);
+       free(ictx);
+
+       return NULL;
+}
+
+void tfm_interface_exit(struct tfm_interface_context *ictx)
+{
+       if (!ictx)
+               return;
+
+       tfm_interface_disconnect(ictx->connected);
+       destroy_interface_list(ictx);
+       free(ictx);
+}
diff --git a/src/interface.h b/src/interface.h
new file mode 100644 (file)
index 0000000..7bb9c02
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * flash-manager - Tizen kernel-level image flashing solution
+ *
+ * Licensed 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.
+ */
+
+#ifndef __INTERFACE_H
+#define __INTERFACE_H
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+typedef LIST_HEAD(availlist, tfm_interface_driver) INTERFACE;
+
+#define INTERFACE_REGISTER(_intf) extern INTERFACE interface_avail_list;       \
+static void __attribute__ ((constructor)) tfm_##_intf##_interface_init(void)   \
+{                                                                              \
+       LIST_INSERT_HEAD(&interface_avail_list, &_intf, entry);                 \
+}
+
+struct tfm_interface_context;
+struct tfm_interface;
+
+struct tfm_interface_ops {
+       int (*connect)(struct tfm_interface *intf);
+       int (*disconnect)(struct tfm_interface *intf);
+       ssize_t (*rx_data)(int fd, void *buf, ssize_t len);
+       ssize_t (*tx_data)(int fd, void *buf, ssize_t len);
+};
+
+struct tfm_interface_driver {
+       char *name;
+       struct tfm_interface_ops ops;
+
+       LIST_ENTRY(tfm_interface_driver) entry;
+};
+
+struct tfm_interface {
+       char *name;
+       int rxd;
+       int txd;
+       struct tfm_interface_ops *ops;
+
+       void *priv;
+       pthread_t tid;
+       struct tfm_interface_context *ctx;
+
+       LIST_ENTRY(tfm_interface) entry;
+};
+
+ssize_t tfm_interface_send(struct tfm_interface *intf, void *buf, ssize_t len);
+ssize_t tfm_interface_recv(struct tfm_interface *intf, void *buf, ssize_t len);
+int tfm_interface_set_private(struct tfm_interface_context *ictx,
+                                       char *name, void *data);
+struct tfm_interface *tfm_interface_connect(struct tfm_interface_context *ictx);
+void tfm_interface_disconnect(struct tfm_interface *intf);
+struct tfm_interface_context *tfm_interface_init(void);
+void tfm_interface_exit(struct tfm_interface_context *ictx);
+#endif