--- /dev/null
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "libaltos_private.h"
+#include "libaltos_posix.h"
+
+void
+altos_set_last_posix_error(void)
+{
+ altos_set_last_error(errno, strerror(errno));
+}
+
+PUBLIC struct altos_file *
+altos_open(struct altos_device *device)
+{
+ struct altos_file_posix *file = calloc (sizeof (struct altos_file_posix), 1);
+ int ret;
+ struct termios term;
+
+ if (!file) {
+ altos_set_last_posix_error();
+ return NULL;
+ }
+
+// altos_set_last_error(12, "yeah yeah, failed again");
+// free(file);
+// return NULL;
+
+ file->fd = open(device->path, O_RDWR | O_NOCTTY);
+ if (file->fd < 0) {
+ altos_set_last_posix_error();
+ free(file);
+ return NULL;
+ }
+#ifdef USE_POLL
+ pipe(file->pipe);
+#else
+ file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
+ if (file->out_fd < 0) {
+ altos_set_last_posix_error();
+ close(file->fd);
+ free(file);
+ return NULL;
+ }
+#endif
+ ret = tcgetattr(file->fd, &term);
+ if (ret < 0) {
+ altos_set_last_posix_error();
+ close(file->fd);
+#ifndef USE_POLL
+ close(file->out_fd);
+#endif
+ free(file);
+ return NULL;
+ }
+ cfmakeraw(&term);
+ cfsetospeed(&term, B9600);
+ cfsetispeed(&term, B9600);
+#ifdef USE_POLL
+ term.c_cc[VMIN] = 1;
+ term.c_cc[VTIME] = 0;
+#else
+ term.c_cc[VMIN] = 0;
+ term.c_cc[VTIME] = 1;
+#endif
+ ret = tcsetattr(file->fd, TCSAFLUSH, &term);
+ if (ret < 0) {
+ altos_set_last_posix_error();
+ close(file->fd);
+#ifndef USE_POLL
+ close(file->out_fd);
+#endif
+ free(file);
+ return NULL;
+ }
+ return &file->file;
+}
+
+PUBLIC void
+altos_close(struct altos_file *file_common)
+{
+ struct altos_file_posix *file = (struct altos_file_posix *) file_common;
+
+ if (file->fd != -1) {
+ int fd = file->fd;
+ file->fd = -1;
+#ifdef USE_POLL
+ write(file->pipe[1], "\r", 1);
+#else
+ close(file->out_fd);
+ file->out_fd = -1;
+#endif
+ close(fd);
+ }
+}
+
+PUBLIC int
+altos_flush(struct altos_file *file_common)
+{
+ struct altos_file_posix *file = (struct altos_file_posix *) file_common;
+
+ if (file->file.out_used && 0) {
+ printf ("flush \"");
+ fwrite(file->file.out_data, 1, file->file.out_used, stdout);
+ printf ("\"\n");
+ }
+ while (file->file.out_used) {
+ int ret;
+
+ if (file->fd < 0)
+ return -EBADF;
+#ifdef USE_POLL
+ ret = write (file->fd, file->file.out_data, file->file.out_used);
+#else
+ ret = write (file->out_fd, file->file.out_data, file->file.out_used);
+#endif
+ if (ret < 0) {
+ altos_set_last_posix_error();
+ return -altos_last_error.code;
+ }
+ if (ret) {
+ memmove(file->file.out_data, file->file.out_data + ret,
+ file->file.out_used - ret);
+ file->file.out_used -= ret;
+ }
+ }
+ return 0;
+}
+
+
+#ifdef USE_POLL
+#include <poll.h>
+#endif
+
+int
+altos_fill(struct altos_file *file_common, int timeout)
+{
+ struct altos_file_posix *file = (struct altos_file_posix *) file_common;
+
+ int ret;
+#ifdef USE_POLL
+ struct pollfd fd[2];
+#endif
+ if (timeout == 0)
+ timeout = -1;
+ while (file->file.in_read == file->file.in_used) {
+ if (file->fd < 0)
+ return LIBALTOS_ERROR;
+#ifdef USE_POLL
+ fd[0].fd = file->fd;
+ fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
+ fd[1].fd = file->pipe[0];
+ fd[1].events = POLLIN;
+ ret = poll(fd, 2, timeout);
+ if (ret < 0) {
+ altos_set_last_posix_error();
+ return LIBALTOS_ERROR;
+ }
+ if (ret == 0)
+ return LIBALTOS_TIMEOUT;
+
+ if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
+ return LIBALTOS_ERROR;
+ if (fd[0].revents & POLLIN)
+#endif
+ {
+ ret = read(file->fd, file->file.in_data, USB_BUF_SIZE);
+ if (ret < 0) {
+ altos_set_last_posix_error();
+ return LIBALTOS_ERROR;
+ }
+ file->file.in_read = 0;
+ file->file.in_used = ret;
+#ifndef USE_POLL
+ if (ret == 0 && timeout > 0)
+ return LIBALTOS_TIMEOUT;
+#endif
+ }
+ }
+ if (file->file.in_used && 0) {
+ printf ("fill \"");
+ fwrite(file->file.in_data, 1, file->file.in_used, stdout);
+ printf ("\"\n");
+ }
+ return 0;
+}
+