diff options
Diffstat (limited to 'debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/linuxusb.c')
-rw-r--r-- | debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/linuxusb.c | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/linuxusb.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/linuxusb.c new file mode 100644 index 00000000..a662a01f --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/linuxusb.c @@ -0,0 +1,400 @@ +/* + * $Id: linuxusb.c,v 1.24 2006/10/12 14:21:22 desrod Exp $ + * + * linuxusb.c: device i/o for linux usb + * + * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This library 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-usb.h" +#include "pi-error.h" + +#ifdef HAVE_SYS_IOCTL_COMPAT_H +#include <sys/ioctl_compat.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + + +static int u_open(pi_socket_t *ps, struct pi_sockaddr *addr, size_t addrlen); +static int u_close(pi_socket_t *ps); +static int u_write(pi_socket_t *ps, unsigned char *buf, size_t len, int flags); +static int u_read(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags); +static int u_poll(pi_socket_t *ps, int timeout); +static int u_flush(pi_socket_t *ps, int flags); + +void pi_usb_impl_init (struct pi_usb_impl *impl) +{ + impl->open = u_open; + impl->close = u_close; + impl->write = u_write; + impl->read = u_read; + impl->flush = u_flush; + impl->poll = u_poll; + impl->wait_for_device = NULL; /* not implemented in linuxusb yet */ + impl->changebaud = NULL; /* we don't need this one on linuxusb + * as USB serial adapters redirect to serial ports + */ + impl->control_request = NULL; +} + + +/*********************************************************************** + * + * Function: u_open + * + * Summary: Open the usb port and establish a connection for + * + * Parameters: None + * + * Returns: The file descriptor + * + ***********************************************************************/ +static int +u_open(pi_socket_t *ps, struct pi_sockaddr *addr, size_t addrlen) +{ + int fd, + i; + char *tty = addr->pi_device; + + if ((fd = open(tty, O_RDWR | O_NONBLOCK)) < 0) { + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; /* errno already set */ + } + + if (!isatty(fd)) { + close(fd); + errno = EINVAL; + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; + } + + if ((i = fcntl(fd, F_GETFL, 0)) != -1) { + i &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, i); + } + + if ((i = pi_socket_setsd(ps, fd)) < 0) + return i; + + return fd; +} + + +/*********************************************************************** + * + * Function: u_close + * + * Summary: Close the open socket/file descriptor + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +static int +u_close(pi_socket_t *ps) +{ + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV CLOSE linuxusb fd: %d\n", ps->sd)); + + return close(ps->sd); +} + + +/*********************************************************************** + * + * Function: u_poll + * + * Summary: Poll the open socket/file descriptor + * + * Parameters: None + * + * Returns: 1 on success, PI_ERR_SOCK_TIMEOUT on timeout + * + ***********************************************************************/ +static int +u_poll(pi_socket_t *ps, int timeout) +{ + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + if (timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + select(ps->sd + 1, &ready, 0, 0, &t); + } + + if (!FD_ISSET(ps->sd, &ready)) { + /* otherwise throw out any current packet and return */ + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV POLL linuxusb timeout\n")); + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV POLL linuxusb found data on fd: %d\n", ps->sd)); + + return 1; +} + + +/*********************************************************************** + * + * Function: u_write + * + * Summary: Write to the open socket/file descriptor + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +static int +u_write(pi_socket_t *ps, unsigned char *buf, size_t len, int flags) +{ + int total, + nwrote; + struct pi_usb_data *data = (struct pi_usb_data *)ps->device->data; + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + total = len; + while (total > 0) { + if (data->timeout == 0) + select(ps->sd + 1, 0, &ready, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, 0, &ready, 0, &t)) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + if (!FD_ISSET(ps->sd, &ready)) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + nwrote = write(ps->sd, buf, len); + if (nwrote < 0) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + total -= nwrote; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV TX linuxusb wrote %d bytes\n", len)); + + return len; +} + + +/*********************************************************************** + * + * Function: u_read_buf + * + * Summary: read buffer + * + * Parameters: pi_socket_t*, char* to buffer, length of buffer + * + * Returns: number of bytes read + * + ***********************************************************************/ +static int +u_read_buf (pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + struct pi_usb_data *data = (struct pi_usb_data *)ps->device->data; + size_t rbuf = data->buf_size; + + if (rbuf > len) + rbuf = len; + + if (pi_buffer_append (buf, data->buf, rbuf) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + if (flags != PI_MSG_PEEK) { + data->buf_size -= rbuf; + if (data->buf_size > 0) + memmove(data->buf, &data->buf[rbuf], data->buf_size); + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV RX linuxusb read %d bytes from read-ahead buffer\n", rbuf)); + + return rbuf; +} + + +/*********************************************************************** + * + * Function: u_read + * + * Summary: Read incoming data from the socket/file descriptor + * + * Parameters: pi_socket_t*, char* to buffer, buffer length, flags + * + * Returns: number of bytes read or negative otherwise + * + ***********************************************************************/ +static int +u_read(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + ssize_t rbuf = 0, + bytes; + struct pi_usb_data *data = (struct pi_usb_data *)ps->device->data; + struct timeval t; + fd_set ready; + + /* check whether we have at least partial data in store */ + if (data->buf_size) { + rbuf = u_read_buf(ps, buf, len, flags); + if (rbuf < 0) + return rbuf; + len -= rbuf; + if (len == 0) + return rbuf; + } + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + if (data->timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, &ready, 0, 0, &t) == 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV RX linuxusb timeout\n")); + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + } + + /* If data is available in time, read it */ + if (FD_ISSET(ps->sd, &ready)) { + if (flags == PI_MSG_PEEK && len > 256) + len = 256; + + if (pi_buffer_expect (buf, len) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + bytes = read(ps->sd, buf->data + buf->used, len); + + if (bytes > 0) { + if (flags == PI_MSG_PEEK) { + memcpy(data->buf + data->buf_size, buf->data + buf->used, bytes); + data->buf_size += bytes; + } + buf->used += bytes; + rbuf += bytes; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV RX linuxusb read %d bytes\n", bytes)); + } + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV RX linuxusb timeout\n")); + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + return rbuf; +} + +/*********************************************************************** + * + * Function: u_flush + * + * Summary: Flush incoming and/or outgoing data from the socket/file + * descriptor + * + * Parameters: ps is of type pi_socket that contains the sd member which is + * the file descriptor that the data in buf will be read. It + * also contains the read buffer. + * + * flags is of type int and can be a combination of + * PI_FLUSH_INPUT and PI_FLUSH_OUTPUT + * + * Returns: 0 + * + ***********************************************************************/ +static int +u_flush(pi_socket_t *ps, int flags) +{ + char buf[256]; + int fl; + struct pi_usb_data *data = (struct pi_usb_data *) ps->device->data; + + if (flags & PI_FLUSH_INPUT) { + /* clear internal buffer */ + data->buf_size = 0; + + /* flush pending data */ + if ((fl = fcntl(ps->sd, F_GETFL, 0)) != -1) { + fcntl(ps->sd, F_SETFL, fl | O_NONBLOCK); + while (recv(ps->sd, buf, sizeof(buf), 0) > 0) + ; + fcntl(ps->sd, F_SETFL, 0); + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV FLUSH linuxusb flushed input buffer\n")); + } + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ |