Show misc_serial.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* libmisc: utilities for dealing with serial ports
*
* $Id: misc_serial.c,v 1.8 2005/12/07 03:11:45 jelson Exp $
*/
char misc_serial_cvsid[] = "$Id: misc_serial.c,v 1.8 2005/12/07 03:11:45 jelson Exp $";
#include "misc.h"
#include <termios.h>
#ifndef IN_CYGWIN
#include <linux/serial.h>
#endif
int misc_convert_baud(int baud_int)
{
int baud = 0;
switch (baud_int) {
case 300: baud = B300; break;
case 1200: baud = B1200; break;
case 2400: baud = B2400; break;
case 4800: baud = B4800; break;
case 9600: baud = B9600; break;
case 19200: baud = B19200; break;
case 38400: baud = B38400; break;
case 57600: baud = B57600; break;
case 115200: baud = B115200; break;
case 230400: baud = B230400; break;
default: baud = 0;
elog(LOG_ERR, "Unsupported serial speed: %d\n", baud_int);
}
return baud;
}
int misc_config_serial(int fd, int baud_int, int rtscts)
{
struct termios t;
int baud;
int special_rate = 0;
/* handle faster, nonstandard rates */
if (baud_int > 230400) {
elog(LOG_DEBUG(0), "Setting custom serial speed: %d\n", baud_int);
special_rate = 1;
baud = B38400;
}
else {
if ((baud = misc_convert_baud(baud_int)) == 0)
return -1;
}
memset(&t, 0, sizeof(struct termios));
t.c_cflag = (rtscts?CRTSCTS:0) | CS8 | CREAD | CLOCAL | HUPCL;
t.c_lflag = 0;
t.c_oflag = 0;
t.c_iflag = 0;
cfsetispeed(&t,B0);
cfsetospeed(&t,baud);
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &t) < 0) {
elog(LOG_ERR, "can't set serial properties: %m");
return -1;
}
#ifndef IN_CYGWIN
if (special_rate) {
/*
so, here's the lowdown:
the underlying serial drivers only understand the enum values
in the baud_to_enum function. see /usr/include/bits/termios.h.
there are a few way to set a non-standard rate. there is a
rather large, but totally incomprehensible comment in
/usr/src/linux/drivers/usb/serial/ftdi_sio.c that explains this.
to summarize, here are the ways. we use (3):
1. standard baud rates are set in tty->termios->c_cflag. so,
set tty->termios->c_cflag speed to B38400; set real speed in
tty->alt_speed; this gets ignored if either you set alt_speed
to 0.
2. standard baud rates are set in tty->termios->c_cflag. so,
set tty->termios->c_cflag speed to B38400; call
the TIOCSSERIAL ioctl with (struct serial_struct) set as
follows: flags |= ASYNC_SPD_[HI, VHI, SHI, WARP]; this just
sets alt_speed to (HI: 57600, VHI: 115200, SHI: 230400,
or WARP: 460800) respectively.
3. set tty->termios->c_cflag speed to B38400. call TIOCSSERIAL
ioctl with struct serial_struct set as follows:
flags |= ASYNC_SPD_CUST
custom_divisor = baud_base / your_new_baudrate
*/
struct serial_struct ss;
ioctl(fd, TIOCGSERIAL, &ss);
ss.flags |= ASYNC_SPD_CUST;
ss.custom_divisor = ss.baud_base / baud_int;
ioctl(fd, TIOCSSERIAL, &ss);
}
#endif
return 0;
}
int misc_config_serial_parity(int fd, int baud_int, int rtscts, int odd)
{
struct termios t;
if (misc_config_serial(fd, baud_int, rtscts) < 0)
return -1;
tcgetattr(fd, &t);
t.c_cflag |= PARENB;
if (odd) t.c_cflag |= PARODD;
if (tcsetattr(fd, TCSANOW, &t) < 0) {
elog(LOG_ERR, "can't set serial properties: %m");
return -1;
}
return 0;
}
See more files for this project here