/* * tmc.c - Device-independent TMC functions * * Copyright (C) 2008 by OpenMoko, Inc. * Written by Werner Almesberger * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include "io.h" #include "tmc.h" struct tmc_dsc { const struct proto_ops *ops; /* protocol operations */ void *proto_dsc; /* protocol descriptor */ void *io_dsc; /* I/O descriptor */ int running; /* asynchronous streaming is running */ pthread_t thread; /* streaming thread */ char *repeat; /* command to send to repeat async. */ }; struct tmc_dsc *tmc_open(const struct proto_ops *ops, int argc, const char **argv) { struct tmc_dsc *dsc; dsc = malloc(sizeof(*dsc)); if (!dsc) { perror("malloc"); return NULL; } dsc->ops = ops; dsc->proto_dsc = ops->open(argc, argv); dsc->running = 0; if (dsc->proto_dsc) { if (!ops->dci(dsc->proto_dsc)) return dsc; ops->close(dsc->proto_dsc); } free(dsc); return NULL; } int tmc_close(struct tmc_dsc *dsc) { if (dsc->running) tmc_stop(dsc); dsc->ops->close(dsc->proto_dsc); return 0; } int tmc_send(struct tmc_dsc *dsc, int argc, const char **argv) { int i; for (i = 0; i != argc; i++) if (dsc->ops->write(dsc->proto_dsc, argv[i], strlen(argv[i]))) return -1; return 0; } int tmc_read(struct tmc_dsc *dsc, void *buf, ssize_t size) { void *io_dsc; if (dsc->running) { fprintf(stderr, "can't read in asynchronous mode\n"); return -1; } io_dsc = io_create_buf(); if (dsc->ops->read(dsc->proto_dsc, io_push_buf, io_dsc) < 0) { io_cancel_buf(io_dsc); return -1; } return io_read_buf(io_dsc, buf, size); } static void *launch(void *arg) { struct tmc_dsc *dsc = arg; while (1) { pthread_testcancel(); if (dsc->ops->read(dsc->proto_dsc, io_push_async, dsc->io_dsc) < 0) return NULL; if (!dsc->repeat) return NULL; if (dsc->ops->write(dsc->proto_dsc, dsc->repeat, strlen(dsc->repeat))) return NULL; } return NULL; } int tmc_start(struct tmc_dsc *dsc, const char *file, const char *repeat) { int err; if (dsc->running) { fprintf(stderr, "tmc_start: already running\n"); return -1; } dsc->io_dsc = io_setup_async(file); if (!dsc->io_dsc) return -1; if (!repeat) dsc->repeat = NULL; else { dsc->repeat = strdup(repeat); if (!dsc->repeat) { io_end_async(dsc->io_dsc); return -1; } } dsc->running = 1; err = pthread_create(&dsc->thread, NULL, launch, dsc); if (err) { fprintf(stderr, "pthread_create: %s\n", strerror(err)); return -1; } return 0; } int tmc_stop(struct tmc_dsc *dsc) { int err; if (!dsc->running) { fprintf(stderr, "tmc_stop: not running\n"); return -1; } err = pthread_cancel(dsc->thread); if (err) { fprintf(stderr, "pthread_cancel: %s\n", strerror(err)); } err = pthread_join(dsc->thread, NULL); if (err) { fprintf(stderr, "pthread_join: %s\n", strerror(err)); } dsc->running = 0; io_end_async(dsc->io_dsc); free(dsc->repeat); dsc->ops->dci(dsc->proto_dsc); return 0; } void tmc_debug(int level) { debug = level; } const struct proto_ops *tmc_ops(const char *name) { static struct { const char *name; const struct proto_ops *ops; } ops[] = { { "tty", &tty_ops }, { "telnet", &telnet_ops }, { "usbtmc", &usbtmc_ops }, { NULL, NULL } }, *p; for (p = ops; p->name; p++) if (!strcmp(p->name, name)) return p->ops; return NULL; }