diff options
Diffstat (limited to 'libaltos/libaltos_posix.c')
| -rw-r--r-- | libaltos/libaltos_posix.c | 201 | 
1 files changed, 201 insertions, 0 deletions
| diff --git a/libaltos/libaltos_posix.c b/libaltos/libaltos_posix.c new file mode 100644 index 00000000..731e9aa1 --- /dev/null +++ b/libaltos/libaltos_posix.c @@ -0,0 +1,201 @@ +/* + * 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; +} + | 
