You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
718 lines
18 KiB
718 lines
18 KiB
/*
|
|
* $Id: serial.c,v 1.72 2006/10/12 14:21:22 desrod Exp $
|
|
*
|
|
* serial.c: Interface layer to serial HotSync connections
|
|
*
|
|
* Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski
|
|
* Copyright (c) 1999, Tilo Christ
|
|
* Copyright (c) 2005, Florent Pillet
|
|
*
|
|
* 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.
|
|
*
|
|
* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h> /* Needed for Redhat 6.x machines */
|
|
#include <unistd.h>
|
|
|
|
#include "pi-debug.h"
|
|
#include "pi-source.h"
|
|
#include "pi-socket.h"
|
|
#include "pi-serial.h"
|
|
#include "pi-net.h"
|
|
#include "pi-cmp.h"
|
|
#include "pi-error.h"
|
|
#include "pi-util.h"
|
|
|
|
#ifdef OS2
|
|
#include <sys/select.h>
|
|
#endif
|
|
|
|
/* Declare prototypes */
|
|
static int pi_serial_connect(pi_socket_t *ps, struct sockaddr *addr,
|
|
size_t addrlen);
|
|
static int pi_serial_bind(pi_socket_t *ps, struct sockaddr *addr,
|
|
size_t addrlen);
|
|
static int pi_serial_listen(pi_socket_t *ps, int backlog);
|
|
static int pi_serial_accept(pi_socket_t *ps, struct sockaddr *addr,
|
|
size_t *addrlen);
|
|
static int pi_serial_getsockopt(pi_socket_t *ps, int level,
|
|
int option_name, void *option_value,
|
|
size_t *option_len);
|
|
static int pi_serial_setsockopt(pi_socket_t *ps, int level,
|
|
int option_name, const void *option_value,
|
|
size_t *option_len);
|
|
static int pi_serial_close(pi_socket_t *ps);
|
|
|
|
extern int pi_socket_init(pi_socket_t *ps);
|
|
|
|
|
|
/* Protocol Functions */
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_protocol_dup
|
|
*
|
|
* Summary: clones an existing pi_protocol struct
|
|
*
|
|
* Parameters: pi_protocol*
|
|
*
|
|
* Returns: pi_protocol_t* or NULL if operation failed
|
|
*
|
|
***********************************************************************/
|
|
static pi_protocol_t*
|
|
pi_serial_protocol_dup (pi_protocol_t *prot)
|
|
{
|
|
pi_protocol_t *new_prot;
|
|
|
|
ASSERT (prot != NULL);
|
|
|
|
new_prot = (pi_protocol_t *) malloc(sizeof (pi_protocol_t));
|
|
|
|
if (new_prot != NULL) {
|
|
new_prot->level = prot->level;
|
|
new_prot->dup = prot->dup;
|
|
new_prot->free = prot->free;
|
|
new_prot->read = prot->read;
|
|
new_prot->write = prot->write;
|
|
new_prot->flush = prot->flush;
|
|
new_prot->getsockopt = prot->getsockopt;
|
|
new_prot->setsockopt = prot->setsockopt;
|
|
new_prot->data = NULL;
|
|
}
|
|
|
|
return new_prot;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_protocol_free
|
|
*
|
|
* Summary: frees an existing pi_protocol struct
|
|
*
|
|
* Parameters: pi_protocol*
|
|
*
|
|
* Returns: void
|
|
*
|
|
***********************************************************************/
|
|
static void
|
|
pi_serial_protocol_free (pi_protocol_t *prot)
|
|
{
|
|
ASSERT (prot != NULL);
|
|
|
|
if (prot != NULL)
|
|
free(prot);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_protocol
|
|
*
|
|
* Summary: creates and inits pi_protocol struct instance
|
|
*
|
|
* Parameters: pi_device_t*
|
|
*
|
|
* Returns: pi_protocol_t* or NULL if operation failed
|
|
*
|
|
***********************************************************************/
|
|
static pi_protocol_t*
|
|
pi_serial_protocol (pi_device_t *dev)
|
|
{
|
|
pi_protocol_t *prot;
|
|
struct pi_serial_data *data;
|
|
|
|
ASSERT (dev != NULL);
|
|
|
|
prot = (pi_protocol_t *) malloc(sizeof (pi_protocol_t));
|
|
|
|
data = (struct pi_serial_data *)(dev->data);
|
|
|
|
if (prot != NULL) {
|
|
prot->level = PI_LEVEL_DEV;
|
|
prot->dup = pi_serial_protocol_dup;
|
|
prot->free = pi_serial_protocol_free;
|
|
prot->read = data->impl.read;
|
|
prot->write = data->impl.write;
|
|
prot->flush = data->impl.flush;
|
|
prot->getsockopt = pi_serial_getsockopt;
|
|
prot->setsockopt = pi_serial_setsockopt;
|
|
prot->data = NULL;
|
|
}
|
|
|
|
return prot;
|
|
}
|
|
|
|
|
|
/* Device Functions */
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_device_free
|
|
*
|
|
* Summary: frees an existing pi_device struct
|
|
*
|
|
* Parameters: pi_device_t*
|
|
*
|
|
* Returns: void
|
|
*
|
|
***********************************************************************/
|
|
static void
|
|
pi_serial_device_free (pi_device_t *dev)
|
|
{
|
|
ASSERT (dev != NULL);
|
|
|
|
free(dev->data);
|
|
free(dev);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_device
|
|
*
|
|
* Summary: creates and inits pi_device struct instance
|
|
*
|
|
* Parameters: device type
|
|
*
|
|
* Returns: pi_device_t* or NULL if operation failed
|
|
*
|
|
***********************************************************************/
|
|
pi_device_t*
|
|
pi_serial_device (int type)
|
|
{
|
|
pi_device_t *dev;
|
|
struct pi_serial_data *data;
|
|
|
|
dev = (pi_device_t *) malloc(sizeof (pi_device_t));
|
|
if (dev == NULL)
|
|
return NULL;
|
|
|
|
data = (struct pi_serial_data *) malloc(sizeof (struct pi_serial_data));
|
|
if (data == NULL) {
|
|
free(dev);
|
|
return NULL;
|
|
}
|
|
|
|
dev->free = pi_serial_device_free;
|
|
dev->protocol = pi_serial_protocol;
|
|
dev->bind = pi_serial_bind;
|
|
dev->listen = pi_serial_listen;
|
|
dev->accept = pi_serial_accept;
|
|
dev->connect = pi_serial_connect;
|
|
dev->close = pi_serial_close;
|
|
|
|
switch (type) {
|
|
case PI_SERIAL_DEV:
|
|
pi_serial_impl_init (&data->impl);
|
|
break;
|
|
default:
|
|
pi_serial_impl_init (&data->impl);
|
|
break;
|
|
}
|
|
|
|
data->buf_size = 0;
|
|
data->rate = -1;
|
|
data->establishrate = -1;
|
|
data->establishhighrate = -1;
|
|
data->timeout = 0;
|
|
data->rx_bytes = 0;
|
|
data->rx_errors = 0;
|
|
data->tx_bytes = 0;
|
|
data->tx_errors = 0;
|
|
|
|
dev->data = data;
|
|
|
|
return dev;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_connect
|
|
*
|
|
* Summary: Connect socket to a given address
|
|
*
|
|
* Parameters: pi_socket*, sockaddr*, size_t
|
|
*
|
|
* Returns: A negative number on error, 0 otherwise
|
|
*
|
|
***********************************************************************/
|
|
static int
|
|
pi_serial_connect(pi_socket_t *ps, struct sockaddr *addr,
|
|
size_t addrlen)
|
|
{
|
|
struct pi_serial_data *data =
|
|
(struct pi_serial_data *)ps->device->data;
|
|
struct pi_sockaddr *pa = (struct pi_sockaddr *) addr;
|
|
int err;
|
|
|
|
if (ps->type == PI_SOCK_STREAM) {
|
|
if (ps->protocol == PI_PF_SYS) {
|
|
data->establishrate = data->rate = 57600;
|
|
} else {
|
|
if (data->establishrate == -1)
|
|
get_pilot_rate(&data->establishrate, &data->establishhighrate);
|
|
|
|
/* Mandatory CMP connection rate */
|
|
data->rate = 9600;
|
|
}
|
|
} else if (ps->type == PI_SOCK_RAW) {
|
|
/* Mandatory SysPkt connection rate */
|
|
data->establishrate = data->rate = 57600;
|
|
}
|
|
|
|
if ((err = data->impl.open(ps, pa, addrlen)) < 0)
|
|
return err; /* errno already set */
|
|
|
|
ps->raddr = malloc(addrlen);
|
|
memcpy(ps->raddr, addr, addrlen);
|
|
ps->raddrlen = addrlen;
|
|
ps->laddr = malloc(addrlen);
|
|
memcpy(ps->laddr, addr, addrlen);
|
|
ps->laddrlen = addrlen;
|
|
|
|
if (ps->type == PI_SOCK_STREAM) {
|
|
size_t size;
|
|
switch (ps->cmd) {
|
|
case PI_CMD_CMP:
|
|
if (cmp_tx_handshake(ps) < 0)
|
|
goto fail;
|
|
|
|
size = sizeof(data->rate);
|
|
pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_BAUD,
|
|
&data->rate, &size);
|
|
|
|
if ((err = data->impl.changebaud(ps)) < 0)
|
|
goto fail;
|
|
break;
|
|
|
|
case PI_CMD_NET:
|
|
if ((err = data->impl.changebaud(ps)) < 0)
|
|
goto fail;
|
|
break;
|
|
|
|
case PI_CMD_SYS:
|
|
if ((err = data->impl.changebaud(ps)) < 0)
|
|
goto fail;
|
|
break;
|
|
}
|
|
}
|
|
ps->state = PI_SOCK_CONN_INIT;
|
|
ps->command = 0;
|
|
return 0;
|
|
|
|
fail:
|
|
return err;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_bind
|
|
*
|
|
* Summary: Bind address to a local socket
|
|
*
|
|
* Parameters: pi_socket*, sockaddr*, size_t
|
|
*
|
|
* Returns: A negative number on error, 0 otherwise
|
|
*
|
|
***********************************************************************/
|
|
static int
|
|
pi_serial_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen)
|
|
{
|
|
struct pi_serial_data *data =
|
|
(struct pi_serial_data *)ps->device->data;
|
|
struct pi_sockaddr *pa = (struct pi_sockaddr *) addr;
|
|
int err, count = 0;
|
|
|
|
if (ps->type == PI_SOCK_STREAM) {
|
|
if (data->establishrate == -1)
|
|
get_pilot_rate(&data->establishrate, &data->establishhighrate);
|
|
|
|
/* Mandatory CMP connection rate */
|
|
data->rate = 9600;
|
|
} else if (ps->type == PI_SOCK_RAW) {
|
|
/* Mandatory SysPkt connection rate */
|
|
data->establishrate = data->rate = 57600;
|
|
}
|
|
|
|
begin:
|
|
if ((err = data->impl.open(ps, pa, addrlen)) < 0) {
|
|
int save_errno = errno;
|
|
#ifdef MAXPATHLEN
|
|
char realport[MAXPATHLEN];
|
|
#else
|
|
# ifdef PATH_MAX
|
|
char realport[PATH_MAX];
|
|
# else
|
|
char realport[4096];
|
|
# endif /* PATH_MAX */
|
|
#endif /* MAXPATHLEN */
|
|
|
|
realpath(pa->pi_device, realport);
|
|
errno = save_errno;
|
|
|
|
if (errno == ENOENT) {
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
|
|
" The device %s does not exist..\n",
|
|
pa->pi_device));
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
|
|
" Possible solution:\n\n\tmknod %s c "
|
|
"<major> <minor>\n\n", pa->pi_device));
|
|
} else if (errno == EACCES) {
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
|
|
" Please check the "
|
|
"permissions on %s..\n", realport));
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
|
|
" Possible solution:\n\n\tchmod 0666 "
|
|
"%s\n\n", realport));
|
|
} else if (errno == ENODEV) {
|
|
while (count <= 5) {
|
|
if (isatty(fileno(stdout))) {
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
|
|
"\r Port not connected,"
|
|
" sleeping for 2 seconds, "));
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
|
|
"%d retries..",
|
|
5-count));
|
|
}
|
|
sleep(2);
|
|
count++;
|
|
goto begin;
|
|
}
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
|
|
"\n\n Device not found on %s, \
|
|
Did you hit HotSync?\n\n", realport));
|
|
} else if (errno == EISDIR) {
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
|
|
" The port specified must"
|
|
" contain a device name, and %s was"
|
|
" a directory.\n"
|
|
" Please change that to reference a"
|
|
" real device, and try"
|
|
" again\n\n", pa->pi_device));
|
|
}
|
|
return err;
|
|
}
|
|
ps->raddr = malloc(addrlen);
|
|
memcpy(ps->raddr, addr, addrlen);
|
|
ps->raddrlen = addrlen;
|
|
ps->laddr = malloc(addrlen);
|
|
memcpy(ps->laddr, addr, addrlen);
|
|
ps->laddrlen = addrlen;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_listen
|
|
*
|
|
* Summary: Prepare for incoming connections
|
|
*
|
|
* Parameters: pi_socket*, backlog
|
|
*
|
|
* Returns: 0 for success, negative otherwise
|
|
*
|
|
***********************************************************************/
|
|
static int pi_serial_listen(pi_socket_t *ps, int backlog)
|
|
{
|
|
int result;
|
|
struct pi_serial_data *data =
|
|
(struct pi_serial_data *)ps->device->data;
|
|
|
|
/* ps->rate has been set by bind */
|
|
result = data->impl.changebaud(ps);
|
|
if (result == 0)
|
|
ps->state = PI_SOCK_LISTEN;
|
|
|
|
return result;
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_accept
|
|
*
|
|
* Summary: Accept an incoming connection
|
|
*
|
|
* Parameters: pi_socket*, sockaddr*
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***********************************************************************/
|
|
static int
|
|
pi_serial_accept(pi_socket_t *ps, struct sockaddr *addr,
|
|
size_t *addrlen)
|
|
{
|
|
struct pi_serial_data *data =
|
|
(struct pi_serial_data *)ps->device->data;
|
|
size_t size;
|
|
int err;
|
|
|
|
/* Wait for data */
|
|
#ifdef linux
|
|
if (ps->accept_to) {
|
|
/* shield against losing the first packet */
|
|
int result = data->impl.poll(ps, 1000);
|
|
LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d, poll result: %d.\n", __FILE__, __LINE__, result));
|
|
|
|
if (result < 0) {
|
|
char buf[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
data->impl.write(ps, buf, sizeof (buf), 1000);
|
|
}
|
|
}
|
|
#endif
|
|
if ((err = data->impl.poll(ps, ps->accept_to * 1000)) < 0)
|
|
goto fail;
|
|
|
|
data->timeout = ps->accept_to * 1000;
|
|
|
|
pi_socket_init(ps);
|
|
if (ps->type == PI_SOCK_STREAM) {
|
|
struct timeval tv;
|
|
unsigned char cmp_flags;
|
|
|
|
switch (ps->cmd) {
|
|
case PI_CMD_CMP:
|
|
if ((err = cmp_rx_handshake(ps, data->establishrate, data->establishhighrate)) < 0)
|
|
goto fail;
|
|
|
|
/* propagate the long packet format flag to both command and non-command stacks */
|
|
size = sizeof(cmp_flags);
|
|
pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_FLAGS, &cmp_flags, &size);
|
|
if (cmp_flags & CMP_FL_LONG_PACKET_SUPPORT) {
|
|
int use_long_format = 1;
|
|
size = sizeof(int);
|
|
pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT,
|
|
&use_long_format, &size);
|
|
ps->command ^= 1;
|
|
pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT,
|
|
&use_long_format, &size);
|
|
ps->command ^= 1;
|
|
}
|
|
|
|
/* We always reconfigure our port, no matter what */
|
|
size = sizeof(data->rate);
|
|
pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_BAUD, &data->rate, &size);
|
|
if ((err = data->impl.changebaud(ps)) < 0)
|
|
goto fail;
|
|
|
|
/* Palm device needs some time to reconfigure its port */
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 50000;
|
|
select(0, 0, 0, 0, &tv);
|
|
break;
|
|
|
|
case PI_CMD_NET:
|
|
/* serial/network: make sure we don't split writes. set socket option
|
|
* on both the command and non-command instances of the protocol
|
|
*/
|
|
#ifdef MACOSX
|
|
/* We need to turn fragmentation OFF to improve Bluetooth performance
|
|
* but this code is also used by USB on Linux and Freebsd
|
|
* therefore, only compile it when running OS X
|
|
*/
|
|
{
|
|
int split = 0;
|
|
size_t chunksize = 0;
|
|
|
|
size = sizeof (split);
|
|
pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_SPLIT_WRITES,
|
|
&split, &size);
|
|
size = sizeof (chunksize);
|
|
pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_WRITE_CHUNKSIZE,
|
|
&chunksize, &size);
|
|
|
|
ps->command ^= 1;
|
|
size = sizeof (split);
|
|
pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_SPLIT_WRITES,
|
|
&split, &size);
|
|
size = sizeof (chunksize);
|
|
pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_WRITE_CHUNKSIZE,
|
|
&chunksize, &size);
|
|
ps->command ^= 1;
|
|
}
|
|
#endif
|
|
if ((err = net_rx_handshake(ps)) < 0)
|
|
goto fail;
|
|
break;
|
|
}
|
|
ps->dlprecord = 0;
|
|
}
|
|
|
|
data->timeout = 0;
|
|
ps->command = 0;
|
|
ps->state = PI_SOCK_CONN_ACCEPT;
|
|
|
|
return ps->sd;
|
|
|
|
fail:
|
|
return err;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_getsockopt
|
|
*
|
|
* Summary: get options on socket
|
|
*
|
|
* Parameters: pi_socket*, level, option name, option value, option length
|
|
*
|
|
* Returns: 0 for success, negative otherwise
|
|
*
|
|
***********************************************************************/
|
|
static int
|
|
pi_serial_getsockopt(pi_socket_t *ps, int level, int option_name,
|
|
void *option_value, size_t *option_len)
|
|
{
|
|
struct pi_serial_data *data =
|
|
(struct pi_serial_data *)ps->device->data;
|
|
|
|
switch (option_name) {
|
|
case PI_DEV_RATE:
|
|
if (*option_len != sizeof (data->rate))
|
|
goto error;
|
|
memcpy (option_value, &data->rate, sizeof (data->rate));
|
|
break;
|
|
|
|
case PI_DEV_ESTRATE:
|
|
if (*option_len != sizeof (data->establishrate))
|
|
goto error;
|
|
memcpy (option_value, &data->establishrate, sizeof (data->establishrate));
|
|
break;
|
|
|
|
case PI_DEV_HIGHRATE:
|
|
if (*option_len != sizeof (data->establishhighrate))
|
|
goto error;
|
|
memcpy (option_value, &data->establishhighrate, sizeof (data->establishhighrate));
|
|
break;
|
|
|
|
case PI_DEV_TIMEOUT:
|
|
if (*option_len != sizeof (data->timeout))
|
|
goto error;
|
|
memcpy (option_value, &data->timeout, sizeof (data->timeout));
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
errno = EINVAL;
|
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_setsockopt
|
|
*
|
|
* Summary: set options on socket
|
|
*
|
|
* Parameters: pi_socket*, level, option name, option value, option length
|
|
*
|
|
* Returns: 0 for success, negative otherwise
|
|
*
|
|
***********************************************************************/
|
|
static int
|
|
pi_serial_setsockopt(pi_socket_t *ps, int level, int option_name,
|
|
const void *option_value, size_t *option_len)
|
|
{
|
|
struct pi_serial_data *data =
|
|
(struct pi_serial_data *)ps->device->data;
|
|
|
|
/* FIXME: can't change stuff if already connected */
|
|
switch (option_name) {
|
|
case PI_DEV_ESTRATE:
|
|
if (*option_len != sizeof (data->establishrate))
|
|
goto error;
|
|
memcpy (&data->establishrate, option_value, sizeof (data->establishrate));
|
|
break;
|
|
|
|
case PI_DEV_HIGHRATE:
|
|
if (*option_len != sizeof (data->establishhighrate))
|
|
goto error;
|
|
memcpy (&data->establishhighrate, option_value, sizeof (data->establishhighrate));
|
|
break;
|
|
|
|
case PI_DEV_TIMEOUT:
|
|
if (*option_len != sizeof (data->timeout))
|
|
goto error;
|
|
memcpy (&data->timeout, option_value, sizeof (data->timeout));
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
errno = EINVAL;
|
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pi_serial_close
|
|
*
|
|
* Summary: Close a connection, destroy the socket
|
|
*
|
|
* Parameters: pi_socket*
|
|
*
|
|
* Returns: always 0 for success
|
|
*
|
|
***********************************************************************/
|
|
static int pi_serial_close(pi_socket_t *ps)
|
|
{
|
|
struct pi_serial_data *data =
|
|
(struct pi_serial_data *)ps->device->data;
|
|
|
|
if (ps->sd) {
|
|
data->impl.close (ps);
|
|
ps->sd = 0;
|
|
}
|
|
|
|
if (ps->laddr) {
|
|
free(ps->laddr);
|
|
ps->laddr = NULL;
|
|
}
|
|
|
|
if (ps->raddr) {
|
|
free(ps->raddr);
|
|
ps->raddr = NULL;
|
|
}
|
|
|
|
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: */
|