--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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